持久化存儲(chǔ)與HTTP緩存

本文主要學(xué)習(xí)一下一些高級(jí)的HTTP知識(shí)循帐,例如Session LocalStorage Cache-Control Expires ETag

其實(shí)主要就是涉及到了持久化存儲(chǔ)與緩存的技術(shù)

在此之前已經(jīng)學(xué)習(xí)了Cookie的相關(guān)知識(shí)瞳购,其中Cookie有個(gè)缺點(diǎn)可以人為修改惶洲,有一定的安全隱患。

所以啊央,針對(duì)這個(gè)缺點(diǎn)缔赠,誕生了Session

Session

一般來(lái)說(shuō)Session是基于Cookie實(shí)現(xiàn)的,它利用一個(gè)sessionId把用戶的敏感數(shù)據(jù)隱藏起來(lái),除非暴力窮舉才有可能獲得敏感數(shù)據(jù)功蜓。

sessionId

我們使用Cookie的時(shí)候园爷,一般是服務(wù)器給用戶一個(gè)響應(yīng)頭,設(shè)置Cookie

response.setHeader('Set-Cookie', 'sign_in_email=...;HTTPOnly')

既然Session還是基于Cookie實(shí)現(xiàn)的霞赫,那么還是應(yīng)該在Set-Cookie上搞事情腮介。

//預(yù)先在服務(wù)器端預(yù)留對(duì)象準(zhǔn)備存儲(chǔ)各種session
let sessions = {

}
...
let sessionId = Math.random() * 100000
sessions[sessionId] = {sign_in_email: email}
response.setHeader('Set-Cookie', `sessionId=${sessionId};HTTPOnly`)

使用隨機(jī)數(shù)來(lái)做sessionId,最終只是把這串隨機(jī)數(shù)暴露給外界,而真正的信息卻保存在了服務(wù)器端的sessions對(duì)象里面端衰。它就像一個(gè)密碼簿一樣叠洗,有效的信息與sessionId一一對(duì)應(yīng),這是服務(wù)器的事旅东,保證了安全性灭抑。

當(dāng)下次用戶訪問(wèn)該網(wǎng)站的其他頁(yè)面的時(shí)候,就會(huì)帶著登錄時(shí)服務(wù)器給的這個(gè)sessionId抵代,服務(wù)器獲得這個(gè)sessionId后腾节,然后一轉(zhuǎn)化就知道是正確的用戶了。

let sessions = {
  sessionId: {
    sign_in_email: ...
  }
}

持久化存儲(chǔ)

在HTML里面js文件里面的變量或?qū)ο蠡珉梗慨?dāng)網(wǎng)頁(yè)刷新的時(shí)候案腺,就會(huì)死掉,又重新生成康吵,雖然還是那個(gè)a劈榨,但是刷新后已經(jīng)是另一塊內(nèi)存了。既然它也沒(méi)變晦嵌,我們?yōu)槭裁床话阉恢北A糁赝保词顾⑿铝?code>a還是那個(gè)a,也就是持久化存儲(chǔ)的意義惭载。以前使用Cookie做這個(gè)功能旱函,不過(guò)Cookie每次發(fā)請(qǐng)求會(huì)把Cookie里面的所有東西都帶著去服務(wù)器,加重內(nèi)存的負(fù)擔(dān)描滔,而且請(qǐng)求響應(yīng)時(shí)間長(zhǎng)棒妨,所以html5給了一個(gè)新的API localStorage

關(guān)于Cookie如何工作的,我發(fā)現(xiàn)這篇文章寫得特別好

LocalStorage

它本質(zhì)上還是個(gè)hash含长,不過(guò)是存在于瀏覽器端的靶衍,不同于session存在與服務(wù)器端的hash。一般存儲(chǔ)的都是沒(méi)有用的或者不敏感的信息茎芋。

localStorage是window的全局屬性颅眶,常用的有三個(gè)方法

//1. 添加鍵、值
localStorage.setItem('a', '...')
//2. 獲得鍵田弥、值
localStorage涛酗。getItem('a')
//3.清空l(shuí)ocalStorage
localStorage.clear()

注意,它存的值全是字符串,即使你寫的像對(duì)象也沒(méi)有卵用商叹。

如果想存儲(chǔ)字符串需要用到JSON.stringify( )

全是字符串

一個(gè)實(shí)際應(yīng)用

很簡(jiǎn)單的一個(gè)例子:網(wǎng)站進(jìn)行更新了燕刻,用戶登錄進(jìn)來(lái)了,想提示用戶一下---我有新東西啦剖笙,這個(gè)提示并不應(yīng)該在每次刷新的時(shí)候反復(fù)告訴用戶卵洗,只是在第一次用戶進(jìn)來(lái)的時(shí)候告訴他即可。

 let already = localStorage.getItem('已經(jīng)提示過(guò)了')
 if (!already) {
   alert('我們的網(wǎng)站新進(jìn)了一些貨物弥咪,您看一下有沒(méi)有您需要的啊O(∩_∩)O~')
   localStorage.setItem('已經(jīng)提示過(guò)了', true)
 } else {

}

當(dāng)?shù)谝淮卧L問(wèn)的時(shí)候过蹂,already為null,所以進(jìn)入if代碼片段聚至,提示用戶一次酷勺,接著把already設(shè)為true,不會(huì)進(jìn)入if扳躬,也就不再提示了脆诉。

實(shí)際應(yīng)用

不基于Cookiesession

學(xué)習(xí)了localStorage,就可以搞一些黑科技了贷币,前面說(shuō)了击胜,session一般是基于Cookie的,那么有沒(méi)有例外呢役纹。

有的偶摔。利用查詢參數(shù)和localStorage可是實(shí)現(xiàn)sessionId`。

小結(jié)一下

  1. Cookie的特點(diǎn)
    • 服務(wù)器通過(guò) Set-Cookie 頭給客戶端一串字符串
    • 客戶端每次訪問(wèn)相同域名的網(wǎng)頁(yè)時(shí)字管,必須帶上這段字符串
    • 客戶端要在一段時(shí)間內(nèi)保存這個(gè)Cookie
    • Cookie 默認(rèn)在用戶關(guān)閉頁(yè)面后就失效啰挪,后臺(tái)代碼可以任意設(shè)置 Cookie 的過(guò)期時(shí)間信不。比如max-age和后面要講的Expires
    • 大小大概在 4kb 以內(nèi)
  2. Session的特點(diǎn)
    • 將 SessionID(隨機(jī)數(shù))通過(guò) Cookie 發(fā)給客戶端
    • 客戶端訪問(wèn)服務(wù)器時(shí)嘲叔,服務(wù)器讀取 SessionID
    • 服務(wù)器有一塊內(nèi)存(哈希表)保存了所有 session
    • 通過(guò) SessionID 我們可以得到對(duì)應(yīng)用戶的隱私信息,如 id抽活、email
    • 這塊內(nèi)存(哈希表)就是服務(wù)器上的所有 session
  3. LocalStorage的特點(diǎn)
    • LocalStorage 跟 HTTP 無(wú)關(guān)
    • 也就是說(shuō)發(fā)送任何請(qǐng)求都不會(huì)帶上 LocalStorage 的值
    • 只有相同域名的頁(yè)面才能互相讀取 LocalStorage(沒(méi)有同源那么嚴(yán)格)
    • 每個(gè)域名 localStorage 最大存儲(chǔ)量為 5Mb 左右(每個(gè)瀏覽器不一樣)
    • 常用場(chǎng)景:記錄有沒(méi)有提示過(guò)用戶(沒(méi)有用的信息硫戈,不能記錄密碼等敏感信息)
    • LocalStorage 永久有效,除非用戶清理緩存
清理緩存

SessionStorage

會(huì)話存儲(chǔ)主要特點(diǎn)與localStorage基本相同下硕,最大的不同是SessionStorage在用戶關(guān)閉頁(yè)面(會(huì)話結(jié)束)后就失效丁逝。

HTTP緩存技術(shù)三兄弟

假如說(shuō)我們要訪問(wèn)的的文件比較大,我們請(qǐng)求完之后梭姓,下載需要花很長(zhǎng)時(shí)間霜幼,當(dāng)我們刷新頁(yè)面的時(shí)候,雖然文件沒(méi)有任何更新誉尖,但是我們又從服務(wù)器端下載了一遍大文件罪既,導(dǎo)致每次響應(yīng)時(shí)間依然很長(zhǎng)。

加載時(shí)間很長(zhǎng)

通過(guò)上圖的實(shí)驗(yàn)可以看到localhost的請(qǐng)求響應(yīng)很快,10ms琢感;而default.css丢间、main.js文件較大,響應(yīng)時(shí)間是localhost的25倍驹针,而jq文件使用了cdn加速烘挫,是從內(nèi)存的緩存中獲得的,幾乎瞬間柬甥。如果每次都這樣的話饮六,用戶體驗(yàn)肯定很差。


那么我們能不能在第一次響應(yīng)完畢之后,如果資源沒(méi)有更新,就不去服務(wù)器端下載翼闹,而是去某個(gè)地方獲得呢勇哗?

答案是肯定的,可以實(shí)現(xiàn)法严,通過(guò)緩存,正如上圖的jq實(shí)現(xiàn)的方法一樣。

這部分可以作為web性能優(yōu)化的一個(gè)方法辜膝。

Cache-Control

通過(guò)max-age設(shè)置緩存的有效時(shí)間(持續(xù)時(shí)間)

 if (path === '/css/default.css'){
    let string = fs.readFileSync('./css/default.css', 'utf8')
    response.setHeader('Content-Type', 'text/css;charset=utf-8')
    response.setHeader('Cache-Control', 'max-age=1000000')
    response.write(string)
    response.end()
  }

在響應(yīng)頭里面加上Cache-Control,表示在100000秒內(nèi)不要再去向服務(wù)器要這個(gè)資源了漾肮,就從我的內(nèi)存緩存里面獲得厂抖。

緩存的技術(shù)
多次刷新后

雖然使用了緩存技術(shù),不過(guò)有一點(diǎn)疑惑的就是有時(shí)候從硬盤的緩存里面獲得克懊,這個(gè)速度提升并不大忱辅,但是仍然避免了向服務(wù)器再次發(fā)起請(qǐng)求獲得資源的過(guò)程;有時(shí)候從內(nèi)存的緩存里面獲得谭溉,這個(gè)就特別快了墙懂。大概是因?yàn)閮?nèi)存的緩存特別快吧。

通常我們把Cache-Control的有效時(shí)間設(shè)的很長(zhǎng)扮念。

以經(jīng)常逛得知乎為例损搬。

[圖片上傳失敗...(image-904262-1518244355829)]

如果一個(gè)文件長(zhǎng)期不變,把它設(shè)為從緩存里面獲得柜与,知乎設(shè)置了32596169秒的有效時(shí)間巧勤,超過(guò)了1年=31536000秒的時(shí)間。

首頁(yè)盡量不用緩存技術(shù)

我們刷一些論壇性質(zhì)的或者新聞性質(zhì)的網(wǎng)站弄匕,注重時(shí)效性颅悉,一般會(huì)把爆炸性的、高質(zhì)量的內(nèi)容放到首頁(yè)去迁匠,如果我們看了一會(huì)剩瓶,想刷新看看新的更新的內(nèi)容秕脓,而你設(shè)了緩存,看到的還是10分鐘之前的首頁(yè)儒搭,那就太尷尬了?……

所以首頁(yè)盡量不用緩存技術(shù)吠架,只對(duì)那些長(zhǎng)期不變的文件、圖片等使用緩存技術(shù)搂鲫。

還是以知乎為例傍药。

以知乎為例

對(duì)于知乎的Cache-Control的寫法我是比較懵逼的。

MDN的語(yǔ)法

  1. public

Indicates that the response may be cached by any cache.

  1. private

Indicates that the response is intended for a single user and must not be stored by a shared cache. A private cache may store the response.

  1. no-cache

Forces caches to submit the request to the origin server for validation before releasing a cached copy.

  1. no-store

The cache should not store anything about the client request or server response.

  1. must-revalidate

The cache must verify the status of the stale resources before using it and expired ones should not be used.

MDN推薦關(guān)閉緩存的寫法是Cache-Control: no-cache, no-store, must-revalidate魂仍。

那么如果有的資源確實(shí)被更新了拐辽,如何去更新緩存呢。

更新緩存

通過(guò)服務(wù)器端代碼server.js我們可以發(fā)現(xiàn)

if (path === '/js/main.js') {
  ...
  response.setHeader('Cache-Control', 'max-age=1000000')
  ...
} else if (path === '/css/default.css'){
  ...
  response.setHeader('Cache-Control', 'max-age=1000000')
  ...
}

只要當(dāng)URL符合要求的時(shí)候擦酌,會(huì)使用緩存技術(shù)俱诸,不去發(fā)起請(qǐng)求重新下載資源。

所以當(dāng)文件確實(shí)被更新了之后赊舶,我們可以改變URL睁搭,那么就會(huì)去重新下載新的文件了。

既然我們的網(wǎng)頁(yè)入口是html笼平,可以在這里面動(dòng)手腳

...
<script src="./js/main.js?V2"></script>
...

當(dāng)你更新代碼之后园骆,理論上只需要在URL上添加查詢參數(shù)?V2即可寓调。


我們還是去知乎看看他們的例子锌唾。

更新緩存

可以看到知乎也是把URL改了,只不過(guò)比我那種高級(jí)夺英,它在文件名字動(dòng)了手腳晌涕,大概是用了什么框架或者處理工具吧,不過(guò)更新緩存的思路上是一樣的痛悯。文件變了余黎,知乎就把文件緩存的URL填點(diǎn)東西;沒(méi)變的話灸蟆,就緩存一年驯耻,在你的硬盤某處睡一年_亲族。

小結(jié)一下

使用緩存就用response.setHeader('Cache-Control', 'max-age=100000')炒考,當(dāng)你想更新的時(shí)候就改變文件的URL

緩存技術(shù)

當(dāng)然霎迫,緩存存多了斋枢,你的硬盤估計(jì)就爆了,瀏覽器會(huì)去權(quán)衡這些的知给,應(yīng)該優(yōu)先清楚哪些緩存瓤帚,是瀏覽器的事描姚。

俗話說(shuō)得好啊,吃井不忘挖井人啊戈次,要學(xué)會(huì)憶苦思甜啊轩勘,我們現(xiàn)在用的可爽的Cache-Control也不是憑空冒出來(lái)的,是有歷史原因的怯邪,以前呢绊寻,是用Expires實(shí)現(xiàn)緩存的技術(shù)。

Expires

Expires的英文是到期的意思悬秉,很明顯是與緩存有關(guān)的技術(shù)澄步,不過(guò)從其英文意思也能看出它是到某個(gè)時(shí)間點(diǎn)截止的意思,不是Cache-Control的有效時(shí)間和泌。

MDN的語(yǔ)法

從語(yǔ)法和示例可以看出它是基于格林威治時(shí)間的村缸。

我們還要處理一下時(shí)間

var d = new Date() //Sat Feb 10 2018 11:18:54 GMT+0800 (CST)
d.toGMTString() //"Sat, 10 Feb 2018 03:18:54 GMT"

能看出來(lái),這個(gè)響應(yīng)頭的最大的弊端在于武氓,時(shí)間戳是與你的本地時(shí)間關(guān)聯(lián)的

如果本地電腦的時(shí)間系統(tǒng)錯(cuò)亂了梯皿,而且這種毛病還真的時(shí)常發(fā)生,那你的緩存就毫無(wú)作用了县恕。maybe這就是HTTP要升級(jí)這個(gè)響應(yīng)頭的原因吧O(∩_∩)O~

當(dāng)Cache-ControlExpires共同存在的時(shí)候

如果還有一個(gè) 設(shè)置了 "max-age" 或者 "s-max-age" 指令的Cache-Control響應(yīng)頭索烹,那么 Expires 頭就會(huì)被忽略。

關(guān)于緩存的技術(shù)弱睦,還有最后一個(gè)兄弟ETag百姓,在搞定它之前,先來(lái)學(xué)習(xí)一下它的小跟班MD5

MD5

MD5是一個(gè)摘要算法况木。經(jīng)常用于比較兩個(gè)文件是否完全一樣垒拢,如果有一點(diǎn)不一樣,誤差會(huì)放大火惊。例如我們經(jīng)常重裝系統(tǒng)的話求类,有良心的系統(tǒng)提供者會(huì)給你一個(gè)對(duì)應(yīng)的MD5值,當(dāng)你下載完畢后屹耐,查看你下載的系統(tǒng)的MD5值是否與官方提供給你的一樣尸疆,確保是否會(huì)因?yàn)榫W(wǎng)絡(luò)原因?qū)е履阆螺d的東西不完整。

Linux系統(tǒng)里面使用md5sum指令進(jìn)行MD5校驗(yàn)

MD5校驗(yàn)

第一個(gè)紅框里面就是1.txt文件(內(nèi)容設(shè)定為123456)的MD5值惶岭,第二個(gè)紅框里面就是1-copy文件(內(nèi)容被我改為了123460)的MD5值寿弱。

nodejs里面如何使用呢,Google后發(fā)現(xiàn)有npmMD5按灶。

npm install md5
...
//在server.js引入
var md5 = require('md5');

準(zhǔn)備工作做完症革,可以搞ETag了。

ETag

The ETag HTTP response header is an identifier for a specific version of a resource.It allows caches to be more efficient, and saves bandwidth, as a web server does not need to send a full response if the content has not changed. On the other side, if the content has changed, etags are useful to help prevent simultaneous updates of a resource from overwriting each other ("mid-air collisions").

If the resource at a given URL changes, a new Etag value must be generated. Etags are therefore similar to fingerprints and might also be used for tracking purposes by some servers. A comparison of them allows to quickly determine whether two representations of a resource are the same, but they might also be set to persist indefinitely by a tracking server.

  • 這個(gè)響應(yīng)頭是特定資源版本的標(biāo)識(shí)符鸯旁。
  • 如果給定URL中的資源更改噪矛,則一定要生成新的Etag值量蕊。因此Etags類似于指紋,也可能被某些服務(wù)器用于跟蹤艇挨。 比較etags能快速確定此資源是否變化残炮,但也可能被跟蹤服務(wù)器永久存留。

可以看出ETag應(yīng)該是一串值缩滨,此時(shí)上一節(jié)的MD5就派上用場(chǎng)了吉殃,我們使用MD5來(lái)比較前后兩次請(qǐng)求文件的內(nèi)容。

當(dāng)某個(gè)URL來(lái)訪問(wèn)服務(wù)器的資源的時(shí)候楷怒,如果服務(wù)器設(shè)置了響應(yīng)頭ETag:一串md5值蛋勺,那么

設(shè)置響應(yīng)頭

現(xiàn)在沒(méi)有什么其他變化,如果第二次刷新的話鸠删,你會(huì)發(fā)現(xiàn)

請(qǐng)求頭變了

請(qǐng)求頭多了一個(gè)If-None-Match:一串MD5值抱完。

比較上述兩圖,我的main.js沒(méi)有改變過(guò)刃泡,發(fā)現(xiàn)ETag:一串md5值If-None-Match:一串MD5值的一樣巧娱,稍微一思考的話,就能明白烘贴,第二次刷新的時(shí)候如果我的main.js變了的話禁添,那么

MD5變了

第二次向服務(wù)器發(fā)起請(qǐng)求,下載的main.jsETag的MD5值必然不同了桨踪。

根據(jù)這個(gè)現(xiàn)象老翘,然后結(jié)合MDN文檔

ETag頭的另一個(gè)典型用例是緩存未更改的資源。 如果用戶再次訪問(wèn)給定的URL(設(shè)有ETag字段)锻离,顯示資源過(guò)期了且不可用铺峭,客戶端就發(fā)送值為ETag的If-None -Match header字段:

If-None-Match: "33a64df551425fcc55e4d42a148795d9f25f89d4"

服務(wù)器將客戶端的ETag(作為If-None-Match字段的值一起發(fā)送)與其當(dāng)前版本的資源的ETag進(jìn)行比較,如果兩個(gè)值匹配(即資源未更改)汽纠,服務(wù)器將返回不帶任何內(nèi)容的304未修改狀態(tài)卫键,告訴客戶端緩存版本可用(新鮮)。

可以推理出如下的代碼了:

if (path === '/js/main.js') {
    let string = fs.readFileSync('./js/main.js', 'utf8')
    response.setHeader('Content-Type', 'application/javascript;charset=utf-8')
    let fileMd5 = md5(string)
    response.setHeader('ETag', fileMd5)
    if (request.headers['if-none-match'] === fileMd5) {
      response.statusCode = 304
    } else {
      response.write(string) 
    }
    response.end()
 }

304狀態(tài)碼的含義

HTTP 304 說(shuō)明無(wú)需再次傳輸請(qǐng)求的內(nèi)容虱朵,也就是說(shuō)可以使用緩存的內(nèi)容莉炉。這通常是在一些安全的方法(safe),例如GETHEAD 或在請(qǐng)求中附帶了頭部信息: If-None-MatchIf-Modified-Since碴犬。

304和緩存的區(qū)別:

  1. 緩存不會(huì)發(fā)起請(qǐng)求了絮宁,直接從內(nèi)存或者硬盤中獲得
  2. 304依然會(huì)發(fā)起請(qǐng)求與響應(yīng),只不過(guò)響應(yīng)的第四部分不用再次下載了翅敌,因?yàn)闆](méi)有更改羞福,所以還是第一次下載的資源惕蹄。
304與緩存的區(qū)別

幾個(gè)常見(jiàn)的考題

Cookie和Session的區(qū)別

  1. Cookie是存放在瀏覽器端的數(shù)據(jù)蚯涮,每次都隨請(qǐng)求發(fā)送給 Server治专。存儲(chǔ)cookie是瀏覽器提供的功能。cookie 其實(shí)是存儲(chǔ)在瀏覽器中的純文本遭顶,瀏覽器的安裝目錄下會(huì)專門有一個(gè) cookie 文件夾來(lái)存放各個(gè)域下設(shè)置的cookie张峰。
  2. 而Session是存放在服務(wù)器端的內(nèi)存中,其 Session ID 是通過(guò) Cookie 發(fā)送給客戶端的棒旗,這個(gè)Session ID每次都隨請(qǐng)求發(fā)送給 Server喘批。

Cookie 和 LocalStorage 的區(qū)別

  1. Set-Cookie之后,用戶的每次訪問(wèn)服務(wù)器铣揉,請(qǐng)求里面都會(huì)帶著Cookie到服務(wù)器上饶深,與HTTP有關(guān),而LocalStorage不用發(fā)到服務(wù)器端逛拱,它是存儲(chǔ)在瀏覽器里面的敌厘,與HTTP無(wú)關(guān),是瀏覽器的屬性朽合,window.localStorage俱两。
  2. Cookie一般比較小,大約4k左右曹步,而LocalStorage大約能用5M
  3. Cookie默認(rèn)會(huì)在用戶關(guān)閉頁(yè)面后失效宪彩,不過(guò)后端可以設(shè)置保存時(shí)間,而LocalStorage永久有效讲婚,除非用戶手動(dòng)清理尿孔。

LocalStorage 和 SessionStorage 的區(qū)別

  1. LocalStorage永久有效,除非用戶手動(dòng)清理localStorage.clear()筹麸。不會(huì)自動(dòng)過(guò)期
  2. 但是SessionStorage在會(huì)話結(jié)束后就會(huì)失效纳猫,也就是用戶關(guān)閉了頁(yè)面,就失效了竹捉。會(huì)自動(dòng)過(guò)期

Cookie 如何設(shè)置過(guò)期時(shí)間芜辕?如何刪除 Cookie?

  1. 設(shè)置過(guò)期時(shí)間:Set-Cookie: <cookie-name>=<cookie-value>; Expires=<date>

    data`是格林威治時(shí)間块差,響應(yīng)頭里里面應(yīng)該這么寫代碼

    response.setHeader('Expires', 'Fri, 09 Feb 2018 11:29:48 GMT')
    

    也就是說(shuō)Cookie在格林威治時(shí)間的2018年2月9號(hào)的11點(diǎn)29分48秒失效侵续。

  2. 設(shè)置cookie過(guò)期時(shí)間小于當(dāng)前時(shí)間,那么就會(huì)刪除該cookie憨闰。

function deleteCookie(name) {
  document.cookie = name + '=;  expires=Thu, 01 Jan 1970 00:00:01 GMT;'
}

Cache-Control: max-age=1000 緩存 與 ETag 的「緩存」有什么區(qū)別状蜗?

  1. Cache-Control: max-age=1000的緩存 是直接不發(fā)請(qǐng)求的,1000秒內(nèi)相同URL的用戶請(qǐng)求資源的時(shí)候鹉动,不會(huì)再去發(fā)請(qǐng)求訪問(wèn)服務(wù)器了轧坎,直接從本地內(nèi)存的緩存里面獲取
  2. ETag的緩存是不管怎么樣都要發(fā)起請(qǐng)求,第二次訪問(wèn)的是時(shí)候會(huì)多一個(gè)請(qǐng)求頭If-None-Match : md5值泽示,如果兩次請(qǐng)求之間的MD5值相同就不會(huì)去下載新的文件缸血,響應(yīng)體是第一次下載的蜜氨;如果MD5值變了,就要去下載新的文件捎泻。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末飒炎,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子笆豁,更是在濱河造成了極大的恐慌郎汪,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,470評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件闯狱,死亡現(xiàn)場(chǎng)離奇詭異煞赢,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)哄孤,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,393評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門耕驰,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人录豺,你說(shuō)我怎么就攤上這事朦肘。” “怎么了双饥?”我有些...
    開(kāi)封第一講書人閱讀 162,577評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵媒抠,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我咏花,道長(zhǎng)趴生,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 58,176評(píng)論 1 292
  • 正文 為了忘掉前任昏翰,我火速辦了婚禮苍匆,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘棚菊。我一直安慰自己浸踩,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,189評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布统求。 她就那樣靜靜地躺著检碗,像睡著了一般。 火紅的嫁衣襯著肌膚如雪码邻。 梳的紋絲不亂的頭發(fā)上折剃,一...
    開(kāi)封第一講書人閱讀 51,155評(píng)論 1 299
  • 那天,我揣著相機(jī)與錄音像屋,去河邊找鬼怕犁。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的奏甫。 我是一名探鬼主播戈轿,決...
    沈念sama閱讀 40,041評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼扶檐!你這毒婦竟也來(lái)了凶杖?” 一聲冷哼從身側(cè)響起胁艰,我...
    開(kāi)封第一講書人閱讀 38,903評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤款筑,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后腾么,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體奈梳,經(jīng)...
    沈念sama閱讀 45,319評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,539評(píng)論 2 332
  • 正文 我和宋清朗相戀三年解虱,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了攘须。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,703評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡殴泰,死狀恐怖于宙,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情悍汛,我是刑警寧澤捞魁,帶...
    沈念sama閱讀 35,417評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站离咐,受9級(jí)特大地震影響谱俭,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜宵蛀,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,013評(píng)論 3 325
  • 文/蒙蒙 一昆著、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧术陶,春花似錦凑懂、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,664評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至祟敛,卻和暖如春疤坝,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背馆铁。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 32,818評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工跑揉, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,711評(píng)論 2 368
  • 正文 我出身青樓历谍,卻偏偏與公主長(zhǎng)得像现拒,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子望侈,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,601評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容

  • http協(xié)議有http0.9印蔬,http1.0,http1.1和http2三個(gè)版本脱衙,但是現(xiàn)在瀏覽器使用的是htt...
    一現(xiàn)_閱讀 1,861評(píng)論 0 3
  • 一侥猬、概念(載錄于:http://www.cnblogs.com/EricaMIN1987_IT/p/3837436...
    yuantao123434閱讀 8,348評(píng)論 6 152
  • Http協(xié)議詳解 標(biāo)簽(空格分隔): Linux 聲明:本片文章非原創(chuàng),內(nèi)容來(lái)源于博客園作者M(jìn)IN飛翔的HTTP協(xié)...
    Sivin閱讀 5,222評(píng)論 3 82
  • 深入淺出HTTP協(xié)議(WEB開(kāi)發(fā)和面試必備) 1.基礎(chǔ)概念篇 a.簡(jiǎn)介 HTTP是Hyper Text Trans...
    半世韶華憶闌珊閱讀 1,221評(píng)論 0 7
  • 今日第一次來(lái)到簡(jiǎn)書 朋友介紹 為偶爾想要用文字發(fā)泄情緒找個(gè)地方 大多不懂怎么開(kāi)始 不知道會(huì)不會(huì)有人看得到 看得懂 ...
    方圓不知幾里閱讀 143評(píng)論 0 0