http協議請求響應頭中參數的疑問??

chrome——login.do

chrome——testCache.do

問題1:請求頭中很多參數都是控制緩存的,這些參數就不會有衝突,還是有優先順序之分?

問題2:從第二個圖片可以看出是讀了緩存,返回狀態碼是304,根據判斷最後修改時間來實現(我沒有人為做這個策略,為什麼會自動有?);而第一個頁面沒走緩存,狀態碼是200(這裡怎麼就沒有那個策略了?);其實就是訪問了兩個不同的介面,第二個其實是請求首頁,第一個是登入請求,當然登入請求是要訪問資料庫的,但是登入成後返回的也是首頁,為什麼不走緩存呢?


我給你點建議,涉及到網路協議的問題上論壇提問雖然快捷,但是養成去看RFC的習慣會更好,網路協議這個東西,一知半解就去寫程序,會出很多bug的,穩紮穩打把協議看完了才是正道。


回答第一個問題之前先解釋下HTTP的緩存機制。HTTP緩存機制包含兩種:Freshness以及Validation。

前者設定了一個HTTP響應的有效時間:在這段有效期之內,在獲取到響應之後,接下來無需再次發出實際請求,可以直接從緩存中返回數據。涉及到的HTTP頭有:Expires、Pragma、Cache-Control等(其中Expires、Pragma屬於HTTP/1.0,Cache-Control是HTTP/1.1中引入的)。

而後者是設定了一套校驗規則,用來校驗當前客戶端所緩存的資源是否仍然是新鮮的。而這個校驗通常是發生在前者所設定的有效期失效之時(換言之就是Freshness在前,Validation在後)。當緩存失效時,客戶端會在請求頭中包含前置條件頭,再次向伺服器發送請求,當校驗未失效會返回304 Not Modified,否則就會按原有邏輯完整返回。涉及到的HTTP頭有:ETag、Last-Modified、If-Modified-Since、If-None-Match、If-Range、Cache-Control等。

你會發現Cache-Control在上面兩處都出現過,其實這個HTTP頭可以通過傳入不同的指令,既能控制有效時間又能控制校驗規則。常見的就比如用max-age控制緩存最長持有時間、用must-revalidate控制客戶端每次使用緩存前必須先校驗、用no-store控制客戶端不緩存等。

回到第一個問題中來。圖中的請求頭中包含了Cache-Control、If-Modified-Since、If-None-Match三個,其中「Cache-Control: max-age=0」的目的只是為了讓瀏覽器與源伺服器之間的各級中間代理重新向上游校驗的(因為緩存的有效期變成0了)。我猜你是使用Chrome直接連接Tomcat的,所以是不存在中間代理情況的。剩下If-Modified-Since和If-None-Match。If-None-Match的優先順序高於If-Modified-Since,RFC 7232 - Hypertext Transfer Protocol (HTTP/1.1): Conditional Requests中有具體的優先順序描述。

第二個問題,目前瀏覽器的實現是不會對POST請求的響應做緩存的(從語義上來說也不應該),並且規範中也規定了返回狀態碼不允許是304。不過這並不表示POST的響應不能被緩存,根據RFC 7231 - Hypertext Transfer Protocol (HTTP/1.1): Semantics and Content中描述的,如果在POST請求對應的響應中包含Freshness相關信息的話,這次響應也是可以被緩存,具體可以參考上面的那個鏈接。


首先,你要先比較了解 HTTP 協議里各個方法的定義。例如:GET 和 POST 方法

GET 方法是從指定的資源請求數據

  • GET 請求可被緩存
  • GET 請求保留在瀏覽器歷史記錄中
  • GET 請求可被收藏為書籤
  • GET 請求不應在處理敏感數據時使用
  • GET 請求有長度限制
  • GET 請求只應當用於取回數據

POST 方法向指定資源提交要被處理的數據

  • POST 請求不會被緩存
  • POST 請求不會保留在瀏覽器歷史記錄中
  • POST 不能被收藏為書籤
  • POST 請求對數據長度沒有要求

了解了基本的概念之後,你的第二問答案也很明顯了。第一張圖是用的 POST 方法提交的,所以不會緩存,成功之後返迴響應碼是 200 。
那麼再回答你第一個問題:控制緩存的參數很多,而且是有優先順序的。
從你貼的兩張圖就能找到 Cache-Control,If-Modified-Since,,Expires,,Etag 等等參數

Cache-Control 與 Expires
Cache-Control 與 Expires 作用一致,都是指當前資源的有效期,控制瀏覽器是否直接從瀏覽器獲取數據還是重新發送請求到伺服器取數據。Cache-Control 的選擇更多,設置更細緻,如果同時存在的話,優先順序高於 Expires。

Last-Modified/ETag 與 Cache-Control/Expires
配置 Last-Modified/ETag 的情況下,瀏覽器再次訪問統一 URI 的資源,還是會發送請求到伺服器詢問文件是否已經修改,如果沒有,伺服器會只返回影響嗎 304 (圖第二張圖所示)回給瀏覽器,代表資源沒有變化,告訴瀏覽器直接讀取緩存數據

Cache-Control/Expires 不同,如果檢測到本地的緩存還是有效的時間範圍內,瀏覽器直接使用本地副本,不會發送任何請求。兩者一起使用時,Cache-Control/Expires的優先順序要高於Last-Modified/ETag。即當本地副本根據Cache-Control/Expires發現還在有效期內時,則不會再次發送請求去伺服器詢問修改時間(Last-Modified)或實體標識(Etag)了。

一般情況下,使用 Cache-Control/Expires 會配合 Last-Modified/ETag 一起使用,因為即使伺服器設置緩存時間, 當用戶點擊「刷新」按鈕時,瀏覽器會忽略緩存繼續向伺服器發送請求,這時 Last-Modified/ETag 將能夠很好利用 304 ,從而減少響應開銷。

看到這裡,你也許會問,既然已經有了 Last-Modified 已經能夠知道本地緩存是否是最新的了,為什麼還需要 Etag 呢?

主要是基於以下幾個原因:

  1. Last-Modified 標註的最後修改時間只能精確到秒,如果有些資源在一秒之內被多次修改的話,他就不能準確標註文件的新鮮度了
  2. 如果某些資源會被定期生成,當內容沒有變化,但 Last-Modified 卻改變了,導致文件沒使用緩存
  3. 有可能存在伺服器沒有準確獲取資源修改時間,或者與代理伺服器時間不一致的情形。

Etag 是伺服器自動生成或者由開發者生成的對應資源在伺服器端的唯一標識符,能夠更加準確的控制緩存。Last-Modified 與 ETag 是可以一起使用的,伺服器會優先驗證 ETag,一致的情況下,才會繼續比對 Last-Modified,最後才決定是否返回304。
在圖二中,我們可以清楚的看到 Request Headers 里的 If-None-Match 和 Response Headers Etag 值是完全一致的,所以返回304。

此外,用戶操作也與緩存有關係

通過上表我們可以看到,當用戶在按 F5 進行刷新的時候,會忽略 Expires/Cache-Control 的設置,會再次發送請求去伺服器請求,而 Last-Modified/Etag 還是有效的,伺服器會根據情況判斷返回 304 還是 200;而當用戶使用 Ctrl+F5 進行強制刷新的時候,只是所有的緩存機制都將失效,重新從伺服器拉去資源。不能被緩存的請求

  • HTTP 信息頭中包含Cache-Control:no-cache,pragma:no-cache,或Cache-Control:max-age=0 等告訴瀏覽器不用緩存的請求
  • 需要根據Cookie,認證信息等決定輸入內容的動態請求是不能被緩存的
  • 經過HTTPS安全加密的請求(有人也經過測試發現,ie 其實在頭部加入 Cache-Control:max-age 信息,firefox 在頭部加入 Cache-Control:Public 之後,能夠對HTTPS的資源進行緩存)
  • HTTP 響應頭中不包含 Last-Modified/Etag,也不包含 Cache-Control/Expires 的請求無法被緩存

緩存生效的優先順序可以設的


問題一不同的緩存控制頭有優先順序,第二個問題request中加哪些頭是瀏覽器的行為,取決於本地請求的資源是否是第一次訪問、是否在開發者工具里disable cache等。
具體一些細節可以參考https://github.com/zhangyaowu/blog/blob/master/web/web%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96(%E4%BA%8C)%20%E5%90%88%E7%90%86%E5%88%A9%E7%94%A8%E6%B5%8F%E8%A7%88%E5%99%A8%E7%BC%93%E5%AD%98.md


4141點


rfc2616


推薦閱讀:

HTTP 在什麼情況下會請求超時?
怎樣把 ssh、http 和 https 放到同一埠?
如何看待谷歌 Google 打算用 QUIC 協議替代 TCP/UDP?
http是應用層,ip是網路層,那麼http請求頭部的client ip是怎麼獲取到的呢?
基於傳輸層TCP、UDP協議的自定義應用層協議如何實現?

TAG:計算機網路 | HTTP |