摘要:緩存緩存主要是通過(guò)請(qǐng)求和響應(yīng)報(bào)文頭中的對(duì)應(yīng)信息,來(lái)控制緩存的策略。就會(huì)返回一個(gè)的狀態(tài)碼,表示可以繼續(xù)使用客戶端本地緩存的數(shù)據(jù),并刷新超時(shí)時(shí)間。與之相對(duì)的,則表示當(dāng)前響應(yīng)是針對(duì)單個(gè)用戶的,并非通用數(shù)據(jù),因此不建議任何中間緩存對(duì)其進(jìn)行緩存。
題圖:by @joewakeford
一、序Hi,大家好,我是承香墨影!
HTTP 協(xié)議在網(wǎng)絡(luò)知識(shí)中占據(jù)了重要的地位,HTTP 協(xié)議最基礎(chǔ)的就是請(qǐng)求和響應(yīng)的報(bào)文頭(Header),大多數(shù) Http 協(xié)議的使用方式,都是依賴設(shè)置不同的 HTTP 請(qǐng)求/響應(yīng) 的 Header 來(lái)實(shí)現(xiàn)的。
本系列《實(shí)用 HTTP》就拋開(kāi)常規(guī)的 Header 講解式的表述方式,從實(shí)際問(wèn)題出發(fā),來(lái)分析這些 Http 協(xié)議的使用方式,到底是為了解決什么問(wèn)題?同時(shí)講解它是如何設(shè)計(jì)的和它實(shí)現(xiàn)原理。
HTTP 協(xié)議是一種無(wú)狀態(tài)的“松散協(xié)議”,它不會(huì)記錄不同請(qǐng)求的狀態(tài),并且因?yàn)樗旧戆藘啥耍蛻舳撕头?wù)端),根據(jù)請(qǐng)求和響應(yīng)來(lái)區(qū)分,它大部分的內(nèi)容都只是一個(gè)建議,其實(shí)雙邊是可以不遵守此建議的。例如:服務(wù)端說(shuō),這個(gè)數(shù)據(jù)緩存有一天的時(shí)效性,但是客戶端可以說(shuō),我不聽(tīng)我不聽(tīng),我就要每次去重新請(qǐng)求。
“這里寫了建議零售價(jià) 2 元...”“哦,不接受建議!”
說(shuō)到緩存,本文就來(lái)說(shuō)說(shuō) HTTP 緩存相關(guān)的內(nèi)容。
二、HTTP緩存使用 2.1 為什么需要緩存緩存說(shuō)白了就是為了快,無(wú)論是從磁盤到內(nèi)存還是從網(wǎng)絡(luò)到本地,都是為了在下次實(shí)用此資源的時(shí)候,能夠快速響應(yīng),避免多次的 I/O 操作。
通過(guò)網(wǎng)絡(luò)獲取資源,是一件耗時(shí)的操作,較大的資源還會(huì)需要客戶端和服務(wù)端之間進(jìn)行多次往返通信,這不但會(huì)增加客戶端響應(yīng)的時(shí)間,同時(shí)還會(huì)增加網(wǎng)絡(luò)流量。
在 HTTP 協(xié)議中,天然就有對(duì)緩存的支持,瀏覽器和 App 使用的開(kāi)源網(wǎng)絡(luò)庫(kù)中,都是利用 HTTP 緩存來(lái)實(shí)現(xiàn)對(duì)資源的緩存。
瀏覽器是天然支持 HTTP 緩存,開(kāi)源庫(kù)則需要進(jìn)行一些例如存規(guī)則和緩存的資源存放路徑之類的簡(jiǎn)單設(shè)定。2.2 設(shè)計(jì)一個(gè)緩存策略
那如果讓我們來(lái)設(shè)計(jì)緩存的策略,首先有兩個(gè)重要的指標(biāo)需要考慮。
1. 緩存失效
既然緩存主要是針對(duì)數(shù)據(jù)的復(fù)用,那我們就需要有一個(gè)條件來(lái)判定當(dāng)前緩存的數(shù)據(jù),是否依然有效。
總是不能一次緩存,終身使用吧,我們還需要在緩存失效之后,重新獲取新的數(shù)據(jù)并進(jìn)行緩存。這個(gè)前提就是,緩存都需要有一個(gè)失效的策略。
2. 減少讀取
雖然緩存會(huì)有失效策略,但是這只是客戶端單方面認(rèn)為失效,此時(shí)應(yīng)該再去服務(wù)端重新獲取一遍數(shù)據(jù)。
可有些情況下,其實(shí)資源可能依然有效,并沒(méi)有發(fā)生變動(dòng)。那就需要有一個(gè)策略,讓服務(wù)端通知客戶端,當(dāng)前緩存依然有效,可以繼續(xù)使用。這樣在減少傳輸流量之外,也可以加快相應(yīng)時(shí)間,提高效率。
這就是一個(gè)好的緩存策略必須要考慮的地方,實(shí)際上 HTTP 緩存,也是這樣設(shè)計(jì)的。
2.3 HTTP 緩存HTTP 緩存主要是通過(guò)請(qǐng)求和響應(yīng)報(bào)文頭中的對(duì)應(yīng) Header 信息,來(lái)控制緩存的策略。
這里主要涉及兩個(gè) Header:
Cache-Control:設(shè)定緩存策略,是否使用緩存,超時(shí)時(shí)間是多少。
ETag:當(dāng)前返回?cái)?shù)據(jù)的驗(yàn)證令牌,可能是 Hash 值也可能是其他指紋,主要用于在下次請(qǐng)求的時(shí)候攜帶上,讓服務(wù)端依此判斷當(dāng)前數(shù)據(jù)是否有更改。
服務(wù)端在返回響應(yīng)數(shù)據(jù)的時(shí)候,會(huì)在報(bào)文頭中,增加用于描述當(dāng)前響應(yīng)的內(nèi)容類型、數(shù)據(jù)長(zhǎng)度、緩存策略(Cache-Control)、驗(yàn)證令牌(ETag)等信息。
例如上圖就表示了一次請(qǐng)求響應(yīng)的事務(wù),大概客戶端請(qǐng)求一個(gè)文件的時(shí)候,服務(wù)端返回了一個(gè) 200 的狀態(tài)碼,表示響應(yīng)正常,響應(yīng)的數(shù)據(jù)長(zhǎng)度為 1024 個(gè)字節(jié),建議客戶端將此資源緩存最多 120 秒,并且提供了一個(gè)指紋令牌(“cxmyDev123”),用來(lái)作為當(dāng)前數(shù)據(jù)的唯一標(biāo)識(shí)。
2.4 ETag 數(shù)據(jù)令牌Cache-Control 中設(shè)定的 max-age 很好理解,就是設(shè)定緩存超時(shí)的時(shí)間,HTTP 緩存是限定一個(gè)超時(shí)的秒數(shù),來(lái)確定緩存失效的時(shí)間。
上古時(shí)期還會(huì)使用 expires 來(lái)決定超時(shí)的日期,但是已經(jīng)被廢棄了,如果和 Cache-Control 同時(shí)存在,以 Cache-Control 為準(zhǔn)。
在此時(shí)間間隔范圍內(nèi),客戶端不會(huì)再向服務(wù)端發(fā)送新的請(qǐng)求。當(dāng)資源距離上一次緩存的時(shí)間間隔,大于 120 秒后,客戶端才會(huì)再次向服務(wù)端發(fā)送請(qǐng)求。
假如沒(méi)有數(shù)據(jù)令牌的情況下,大概步驟應(yīng)該是這樣的:
1. 客戶端會(huì)首先找到本地緩存,然后發(fā)現(xiàn)它已經(jīng)失效,無(wú)法再次使用。
2. 客戶端再次向服務(wù)端發(fā)出新的請(qǐng)求,并獲取完整的數(shù)據(jù)再次進(jìn)行緩存。之后再刷新該緩存的超時(shí)時(shí)間。
但是這是一件效率非常低的事情,服務(wù)端并無(wú)法確定所持有的源資源什么時(shí)候會(huì)失效,所以提供的 max-age 值,只是一個(gè)參考值,是需要取平衡的,太短會(huì)導(dǎo)致請(qǐng)求頻繁,太長(zhǎng)又會(huì)導(dǎo)致無(wú)法及時(shí)刷新客戶端資源。而此時(shí)再次請(qǐng)求的時(shí)候,是存在一定的概率,客戶端緩存的數(shù)據(jù)和服務(wù)端上持有的數(shù)據(jù)是一致的,我們就不需要再次對(duì)此數(shù)據(jù)資源進(jìn)行二次緩存,直接使用客戶端之前緩存的數(shù)據(jù)即可,同時(shí)還需要刷新緩存超時(shí)時(shí)間。
這正是數(shù)據(jù)驗(yàn)證令牌(ETag)想要解決的問(wèn)題,服務(wù)端生成并返回的這個(gè)數(shù)據(jù)指紋令牌,通常就是返回?cái)?shù)據(jù)的 Hash 值或者其他數(shù)據(jù)指紋,客戶端無(wú)需關(guān)心它的生成規(guī)則,只需要知道它是當(dāng)前數(shù)據(jù)的一個(gè)唯一標(biāo)識(shí)。
客戶端需要在下次請(qǐng)求時(shí)將其通過(guò) If-None-Match 這個(gè)請(qǐng)求報(bào)文頭,將此驗(yàn)證令牌發(fā)送至服務(wù)端,如果數(shù)據(jù)令牌指紋和服務(wù)端當(dāng)前的數(shù)據(jù)一致,則標(biāo)識(shí)資源未發(fā)生新的變化。就會(huì)返回一個(gè) 304 的狀態(tài)碼,表示可以繼續(xù)使用客戶端本地緩存的數(shù)據(jù),并刷新超時(shí)時(shí)間。注意當(dāng)響應(yīng)碼為 304 的時(shí)候,它是不包含數(shù)據(jù)內(nèi)容的。
通常此緩存操作對(duì)我們都是透明的,它是瀏覽器和開(kāi)源網(wǎng)絡(luò)庫(kù)的基本實(shí)現(xiàn),我們無(wú)需自己去判斷 max-age 和 ETag 的值,這一步我們只需要確定服務(wù)端對(duì)此有支持即可。
這里只是提到了 If-None-Match,它標(biāo)識(shí)比較 ETag 是否不一致,除此之外,還有一些其他的相關(guān)報(bào)文頭,例如 If-Match,有興趣可以查閱相關(guān)資料。2.5 Cache-Control
前面舉的例子中,我們只為 Cache-Control 設(shè)定了一個(gè) max-age,但是其實(shí)還有一些更豐富的配置。
從緩存性能最優(yōu)化的角度來(lái)看,最佳的緩存是無(wú)需與服務(wù)端通信的緩存,可以通過(guò)緩存來(lái)消滅網(wǎng)絡(luò)延遲以及數(shù)據(jù)請(qǐng)求,從而來(lái)提高用戶的體驗(yàn)。
Cache-Control 是在 HTTP/1.1 中被定義的,它可以用于取代之前的緩存策略,現(xiàn)在所有的瀏覽器都支持 Cache-Control ,它已經(jīng)成為一種通用的標(biāo)準(zhǔn)。
Cache-Control 還有一些更靈活的配置,用來(lái)對(duì)緩存做一些更細(xì)致的操作。
1. “no-cache” 和 “no-store”
這兩個(gè)參數(shù)都表示每一次請(qǐng)求,都需要真實(shí)的發(fā)送一個(gè)網(wǎng)絡(luò)請(qǐng)求。
它們之間的區(qū)別在于,“no-cache”并不是真的不緩存數(shù)據(jù),它只是要求每次都確認(rèn)資源是否過(guò)期,也就是它會(huì)利用數(shù)據(jù)令牌 ETag 來(lái)一定程度的減小傳輸?shù)牧髁俊?/p>
而 “no-store” 完全是要求客戶端,每次都重新請(qǐng)求數(shù)據(jù)并下載最新的數(shù)據(jù),不做任何緩存處理。這種不緩存的策略,也包括中間連接的代理、網(wǎng)關(guān) 等中間傳輸?shù)耐ǖ?,也一并不?duì)數(shù)據(jù)進(jìn)行緩存,每次都從源服務(wù)器上獲取數(shù)據(jù)。
2. “public” 和 “private”
“public” 是一種默認(rèn)的策略,表示當(dāng)前緩存是開(kāi)放的,任何請(qǐng)求響應(yīng)的中間環(huán)節(jié),都可以對(duì)其進(jìn)行緩存,如果我們不顯式指定,則當(dāng)前為 “public” 緩存。
與之相對(duì)的 “private”,則表示當(dāng)前響應(yīng)是針對(duì)單個(gè)用戶的,并非通用數(shù)據(jù),因此不建議任何中間緩存對(duì)其進(jìn)行緩存。例如:瀏覽器就是一個(gè)比較私人的緩存源,它會(huì)緩存 “private” 的緩存,而 CDN 則不會(huì)。
三、最佳的緩存策略樹(shù)前面提到,緩存的核心目的就是為了快,能讓下次使用的時(shí)候快速?gòu)?fù)用。所以在理想情況下,我們應(yīng)該將響應(yīng)數(shù)據(jù)盡可能多的緩存,盡可能的緩存足夠長(zhǎng)的時(shí)間,并且為每個(gè)資源提供多帶帶的數(shù)據(jù)驗(yàn)證令牌,以便在時(shí)間過(guò)期之后快速校驗(yàn)。
但是任何事情都是要取其平衡點(diǎn)的,不存在什么最佳緩存策略,并非所有響應(yīng)資源都需要加緩存,這就需要根據(jù)業(yè)務(wù)場(chǎng)景來(lái)設(shè)定。
這里給出一個(gè)增加 HTTP 緩存的通用策略樹(shù),你在對(duì)響應(yīng)增加緩存的時(shí)候,可以參考它來(lái)執(zhí)行。
正常情況下,我們針對(duì)不同的響應(yīng)屬性,會(huì)對(duì)它設(shè)置不同的緩存策略,下面根據(jù)場(chǎng)景,舉幾個(gè)例子。
3.1 用戶相關(guān)的數(shù)據(jù)和單個(gè)用戶緊密相關(guān)的數(shù)據(jù),通常我們是不建議使用緩存的,但是依然存在幾個(gè)等級(jí)。
1. 嚴(yán)格不使用緩存
Cache-Control:no-store
2. 允許客戶終端緩存,但是每次使用都需要確認(rèn)
Cache-Control:no-cache ETag:"cxmyDev1234"
3. 允許客戶終端短時(shí)間緩存
Cache-Control:private max-age=600 ETag:"cxmyDev1234"3.2 通用數(shù)據(jù)
一些通用響應(yīng)資源,更新的頻率非常的低,我們可以根據(jù)需要調(diào)整 max-age 的大小即可。
Cache-Control:max-age=86400 ETag:"cxmyDev1234"四、廢棄和更新緩存的響應(yīng)
緩存的策略,一旦確定并下發(fā)到客戶端,服務(wù)端就失去了對(duì)齊的控制權(quán)。也就是說(shuō),如果我們?cè)O(shè)定了 max-age,在此資源有效期超時(shí)之前,哪怕服務(wù)端的源資源已經(jīng)被替換修改,我們也沒(méi)有一個(gè)合適的時(shí)機(jī)去通知客戶端更新新的響應(yīng)數(shù)據(jù)。
那么有沒(méi)有什么好的策略去標(biāo)記資源廢棄?同時(shí)又能友好的利用緩存策略。
在互聯(lián)網(wǎng)上,所有服務(wù)上的資源,都有一個(gè)對(duì)應(yīng)的 URL(統(tǒng)一資源定位符),它可以明確說(shuō)明如何從一個(gè)精確且固定的位置獲取資源。而 HTTP 緩存,也是依賴于 URL 的,注意 URL 是大小寫敏感的,同一個(gè) URL 表示同一個(gè)請(qǐng)求響應(yīng),依此來(lái)判斷緩存和后續(xù)緩存的復(fù)用。
所以我們是可以在 URL 上做文章的。
4.1 瀏覽器的廢棄策略前面提到,瀏覽器是天然支持 HTTP 緩存的,對(duì)于瀏覽器來(lái)說(shuō),它所面對(duì)的就是一個(gè)個(gè) HTML 頁(yè)面,頁(yè)面內(nèi)會(huì)包含一些 CSS、Image、JavaScript、JSON 資源和數(shù)據(jù)。
針對(duì)不同的資源和數(shù)據(jù),我們可以在其 URL 上,增加數(shù)據(jù)令牌指紋,當(dāng)資源變動(dòng)的時(shí)候,同時(shí)也去刷新改指紋令牌。
到這里就很好理解了:
HTML 頁(yè)面,使用 no-cache,強(qiáng)制每次都向源服務(wù)器確認(rèn)數(shù)據(jù)。
CSS文件通常變動(dòng)的頻率非常低,所以可以允許中間層緩存,并且緩存時(shí)間為一年不過(guò)期。
JavaScript內(nèi)有業(yè)務(wù)邏輯,可以設(shè)定為只允許客戶終端緩存。
getUserInfo,是為個(gè)人用戶數(shù)據(jù)相關(guān),這里推薦可緩存,但是需要每次向服務(wù)器重新確認(rèn)。
4.2 App 接口的緩存策略在 App 中使用的接口,其實(shí)和網(wǎng)頁(yè)又不一樣,HTML 網(wǎng)頁(yè)的結(jié)構(gòu)類似一個(gè)樹(shù)形結(jié)構(gòu),先通過(guò)獲取 .html 文件獲取其內(nèi)所有資源的表,然后依次根據(jù)緩存策略進(jìn)行訪問(wèn)。
但是在 App 中,和服務(wù)器的交互都是通過(guò)數(shù)據(jù)接口來(lái)實(shí)現(xiàn)的,就不存在最開(kāi)始獲取一個(gè)類似 HTML 文件這樣的樹(shù)形接口,每個(gè)接口都是一個(gè)個(gè)“孤島”,可以多帶帶存在。我們就無(wú)法提前知道某個(gè)接口的響應(yīng)數(shù)據(jù)已經(jīng)過(guò)期,同時(shí)也無(wú)法修改 URL 上攜帶的數(shù)據(jù)指紋令牌。
但是其實(shí)我們是可以通過(guò) App 和設(shè)備的一些固有信息,作為 URL 的參數(shù)傳遞,以此來(lái)刷新數(shù)據(jù)。
例如這里 /app/main 獲取主頁(yè)的數(shù)據(jù),這里將當(dāng)前 App 的版本號(hào)當(dāng)參數(shù)拼接在 URL 的后面,以此方式來(lái)強(qiáng)制不同的版本,刷新不同的數(shù)據(jù)。避免剛升級(jí)上來(lái)的 App,還在使用舊版本的數(shù)據(jù)。
這個(gè)例子中,版本號(hào)只是其中一個(gè)維度,如果有必要,還可以傳遞其他維度的信息,例如當(dāng)前網(wǎng)絡(luò)狀態(tài),當(dāng)前用戶 id 等等。
五、小結(jié)到這里我們基本上把 HTTP 的緩存所有相關(guān)的內(nèi)容都講了一遍,這里簡(jiǎn)單總結(jié)一下。
HTTP 緩存依賴 URL 做唯一標(biāo)識(shí),不同的 URL 使用不同的緩存。
Cache-Control 可以控制緩存策略,共有或者私有、緩存超時(shí)時(shí)長(zhǎng)等。
通過(guò) ETag 來(lái)標(biāo)記數(shù)據(jù)指紋令牌,以此來(lái)確定響應(yīng)數(shù)據(jù)是否更新。
應(yīng)該為每個(gè)響應(yīng)資源提供對(duì)應(yīng)的緩存策略。
如果需要廢棄之前的緩存,可以利用修改請(qǐng)求 URL 的方式,將數(shù)據(jù)指紋令牌追加在 URL 之后,以此來(lái)更新數(shù)據(jù)。
關(guān)于 HTTP 緩存,你還有什么更好的想法,可以在留言區(qū)討論。
參考資料:
《HTTP緩存》:http://t.cn/RL1NI8P
《基于緩存策略三要素分解法》
公眾號(hào)后臺(tái)回復(fù)成長(zhǎng)『成長(zhǎng)』,將會(huì)得到我準(zhǔn)備的學(xué)習(xí)資料,也能回復(fù)『加群』,一起學(xué)習(xí)進(jìn)步;你還能回復(fù)『提問(wèn)』,向我發(fā)起提問(wèn)。
推薦閱讀:
小程序 UI 布局指南(一)
程序員的密碼管理之道
手動(dòng)刷新 MediaStore,保存的圖片立即出現(xiàn)在相冊(cè)中
偽代碼、幽默和 Google 的藝術(shù)!
漫畫:App 防止 Fiddler 抓包小技巧!
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/62004.html
摘要:讓你收獲滿滿碼個(gè)蛋從年月日推送第篇文章一年過(guò)去了已累積推文近篇文章,本文為年度精選,共計(jì)篇,按照類別整理便于讀者主題閱讀。本篇文章是今年的最后一篇技術(shù)文章,為了讓大家在家也能好好學(xué)習(xí),特此花了幾個(gè)小時(shí)整理了這些文章。 showImg(https://segmentfault.com/img/remote/1460000013241596); 讓你收獲滿滿! 碼個(gè)蛋從2017年02月20...
摘要:歡迎來(lái)我的個(gè)人站點(diǎn)性能優(yōu)化其他優(yōu)化瀏覽器關(guān)鍵渲染路徑開(kāi)啟性能優(yōu)化之旅高性能滾動(dòng)及頁(yè)面渲染優(yōu)化理論寫法對(duì)壓縮率的影響唯快不破應(yīng)用的個(gè)優(yōu)化步驟進(jìn)階鵝廠大神用直出實(shí)現(xiàn)網(wǎng)頁(yè)瞬開(kāi)緩存網(wǎng)頁(yè)性能管理詳解寫給后端程序員的緩存原理介紹年底補(bǔ)課緩存機(jī)制優(yōu)化動(dòng) 歡迎來(lái)我的個(gè)人站點(diǎn) 性能優(yōu)化 其他 優(yōu)化瀏覽器關(guān)鍵渲染路徑 - 開(kāi)啟性能優(yōu)化之旅 高性能滾動(dòng) scroll 及頁(yè)面渲染優(yōu)化 理論 | HTML寫法...
摘要:歡迎來(lái)我的個(gè)人站點(diǎn)性能優(yōu)化其他優(yōu)化瀏覽器關(guān)鍵渲染路徑開(kāi)啟性能優(yōu)化之旅高性能滾動(dòng)及頁(yè)面渲染優(yōu)化理論寫法對(duì)壓縮率的影響唯快不破應(yīng)用的個(gè)優(yōu)化步驟進(jìn)階鵝廠大神用直出實(shí)現(xiàn)網(wǎng)頁(yè)瞬開(kāi)緩存網(wǎng)頁(yè)性能管理詳解寫給后端程序員的緩存原理介紹年底補(bǔ)課緩存機(jī)制優(yōu)化動(dòng) 歡迎來(lái)我的個(gè)人站點(diǎn) 性能優(yōu)化 其他 優(yōu)化瀏覽器關(guān)鍵渲染路徑 - 開(kāi)啟性能優(yōu)化之旅 高性能滾動(dòng) scroll 及頁(yè)面渲染優(yōu)化 理論 | HTML寫法...
摘要:歡迎來(lái)我的個(gè)人站點(diǎn)性能優(yōu)化其他優(yōu)化瀏覽器關(guān)鍵渲染路徑開(kāi)啟性能優(yōu)化之旅高性能滾動(dòng)及頁(yè)面渲染優(yōu)化理論寫法對(duì)壓縮率的影響唯快不破應(yīng)用的個(gè)優(yōu)化步驟進(jìn)階鵝廠大神用直出實(shí)現(xiàn)網(wǎng)頁(yè)瞬開(kāi)緩存網(wǎng)頁(yè)性能管理詳解寫給后端程序員的緩存原理介紹年底補(bǔ)課緩存機(jī)制優(yōu)化動(dòng) 歡迎來(lái)我的個(gè)人站點(diǎn) 性能優(yōu)化 其他 優(yōu)化瀏覽器關(guān)鍵渲染路徑 - 開(kāi)啟性能優(yōu)化之旅 高性能滾動(dòng) scroll 及頁(yè)面渲染優(yōu)化 理論 | HTML寫法...
閱讀 1428·2021-10-11 11:12
閱讀 3258·2021-09-30 09:46
閱讀 1644·2021-07-28 00:14
閱讀 3147·2019-08-30 13:49
閱讀 2594·2019-08-29 11:27
閱讀 3248·2019-08-26 11:52
閱讀 610·2019-08-23 18:14
閱讀 3447·2019-08-23 16:27