後會無期之jshttp解析(1)

後會無期嗎,http

爲何叫後會無期之jshttp解析,相信咱們不少人都看過各類各樣的http文章教程,可是真的就懂了http了嗎,或許別人問起的時候,仍是沒法具體詳細地解釋,這讓我想起了電影后會無期裏面的臺詞,javascript

從小聽了不少大道理,可依然過很差這一輩子java

正如咱們看了這麼http教程,卻依然沒法真正理解http,究其緣由,就是咱們不少時候都是把http當成一個黑盒子來使用,知道強緩存和協商緩存是幹什麼的,可是缺總記不住請求頭和返回頭

既然如此,那不如讓咱們看看http是怎麼實現的,對於咱們FE來講,最熟悉的語言就是js了,那咱們就經過解讀jshttp這個一系列js實現的http底層的庫來完善咱們最後一個技能點吧node

jshttp是什麼?git

Low-Level JavaScript HTTP-related Modulesgithub

js實現的底層http相關的庫,打開這個庫,咱們能夠發現耳熟能詳的的nodejs大大,TJ、Doug Wilson等都是這個系列的維護者,並且這一些庫被express、koa各類咱們能數的過來的web框架依賴着,是經得起工業考驗的,那麼接下來的我講經過解讀裏面的每一個庫來加深咱們對http的裏面每一個概念的理解web

fresh

此次咱們開篇第一章,解讀是fresh這個庫,首先這個庫是幹什麼的,官方定義express

HTTP response freshness testing瀏覽器

用於檢驗咱們的資源是不是新鮮的,說白了,就是用來處理http緩存的庫。緩存

說到協商緩存,咱們馬上想起Last-ModifiedEtag,就是這兩個返回頭,幫助咱們在服務器校驗文件是否更新了,那服務器是什麼校驗的呢,那就是咱們主角fresh登場了bash

var reqHeaders = { 'if-none-match': '"foo"' }
var resHeaders = { 'etag': '"bar"' }
fresh(reqHeaders, resHeaders)
// => false

var reqHeaders = { 'if-none-match': '"foo"' }
var resHeaders = { 'etag': '"foo"' }
fresh(reqHeaders, resHeaders)
// => true
複製代碼

咱們能夠看到,fresh返回false說明資源已通過期了,返回true的時候說明資源沒有改變,

talk is cheap, show me the code ---linus

深刻代碼

首先看下面代碼,咱們能夠看到fresh傳入兩個參數,reqHeaders是本次發起的請求頭,而resHeaders是服務器對應此次請求的返回頭,若是同時請求頭if-modified-sinceif-none-match都沒有,那麼說明協商緩存失效

function fresh (reqHeaders, resHeaders) {
// fields
  var modifiedSince = reqHeaders['if-modified-since']
  var noneMatch = reqHeaders['if-none-match']

  // unconditional request
  if (!modifiedSince && !noneMatch) {
    return false
  }
  ....
}
複製代碼

那麼若是協商緩存請求頭都存在呢,咱們先看下是否存在強緩存cache-control:no-cache,若是存在,直接返回false

var cacheControl = reqHeaders['cache-control']
  if (cacheControl && CACHE_CONTROL_NO_CACHE_REGEXP.test(cacheControl)) {
    return false
  }
複製代碼

由於Etag的優先級比Last-Modified高,因此接下來會先校驗if-none-match,若是if-none-match存在,且不爲'*',

// if-none-match
  if (noneMatch && noneMatch !== '*') {
    var etag = resHeaders['etag']

    if (!etag) {
      return false
    }

    var etagStale = true
    var matches = parseTokenList(noneMatch)
    for (var i = 0; i < matches.length; i++) {
      var match = matches[i]
      if (match === etag || match === 'W/' + etag || 'W/' + match === etag) {
        etagStale = false
        break
      }
    }

    if (etagStale) {
      return false
    }
  }
複製代碼

爲*的時候,表示

採用其餘方法,尤爲是 PUT,將 If-None-Match used 的值設置爲 * ,用來生成事先並不知道是否存在的文件,能夠確保先前並無進行過相似的上傳操做,防止以前操做數據的丟失。這個問題屬於更新丟失問題的一種。

那不爲*的時候,咱們就要跟服務器將要返回給瀏覽器的etag進行比較,只有etagStale爲true,說明資源改變了,纔會返回false

假設etag和if-none-match的值相等,那麼咱們須要進一步看看是否存在if-modified-since

// if-modified-since
  if (modifiedSince) {
    var lastModified = resHeaders['last-modified']
    var modifiedStale = !lastModified || !(parseHttpDate(lastModified) <= parseHttpDate(modifiedSince))

    if (modifiedStale) {
      return false
    }
  }
複製代碼

若是lastModified爲false或者modifiedSince的時間早於lastModified的時間,說明資源已經被修改了,直接返回false

那麼若是通過上面兩步,都沒有返回false,說明服務器資源都沒有被改變,則直接返回true

總結

怎麼樣,是否是發現服務器處理緩存也就那麼一回事,經過上面的解讀,是否是對協商緩存有了更深的理解,由於咱們已經深刻底層,知道服務器是如何對比文件是否更新了,是否是對接下來的後會無期之jshttp解析系列更有興趣了,關注我,讓咱們一塊兒繼續接下來的jshttp之旅吧

相關文章
相關標籤/搜索