HTTP是由蒂姆·伯納斯-李(TimBerners—Lee)于1989年在歐洲核子研究組織(CERN)所發起。
其中最著名的是 1999 年 6 月公布的RFC 2616[1],定義了HTTP協議中現今廣泛使用的一個版本——HTTP 1.1。
HTTP 是什么全稱:超文本傳輸協議(HyperText Transfer Protocol)。
(相關資料圖)
概念:HTTP是一種能夠獲取像HTML、圖片等網絡資源的通訊協議(protocol)。它是在web上進行數據交換的基礎,是一種client-server協議。
HTTP——因特網的多媒體信使 ——《HTTP權威指南》。HTTP在因特網的角色:充當一個信使的角色,干的就是一個跑腿的活,在客戶端和服務端之間傳遞信息,但我們又不能缺少它。HTTP協議是應用層的協議,是與前端開發最息息相關的協議。平時我們遇到的HTTP請求、HTTP緩存、Cookies、跨域等其實都跟HTTP息息相關。
HTTP 的基礎特性可拓展協議。HTTP 1.0?出現的HTTP headers?讓協議拓展變得更加的容易。只要服務端和客戶端就headers達成語義一致,新功能就可以被輕松的加入進來。HTTP?是無狀態的、有會話的。在同一個連接中,兩個執行成功的HTTP?請求之間是沒有關系的。這就帶來了一個問題,用戶沒有辦法在同一個網站中進行連續的交互,比如在一個電商網站里,用戶把某個商品加入到購物車,切換一個頁面后再次添加了商品,這兩次添加商品的請求之間沒有關聯,瀏覽器無法知道用戶最終選擇了哪些商品。而使用HTTP?的頭部擴展,HTTP Cookies?就可以解決這個問題。把Cookies添加到頭部中,創建一個會話讓每次請求都能共享相同的上下文信息,達成相同的狀態。HTTP?與連接。通過TCP?,或者TLS?——加密的TCP?連接來發送,理論上任何可靠的傳輸協議都可以使用。連接是傳輸層控制的,這從根本上來講不是HTTP的范疇。也就是說,HTTP依賴于面向連接的TCP進行消息傳遞,但連接并不是必須的。只需要它是可靠的,或不丟失消息的(至少返回錯誤)。
HTTP/1.0默認為每一對HTTP請求/響應都打開一個單獨的TCP連接。當需要連續發起多個請求時,這種模式比多個請求共享同一個TCP鏈接更低效。為此,HTTP 1.1持久連接的概念,底層TCP連接可以通過connection頭部實現。但HTTP 1.1在連接上也是不完美的,后面我們會提到。
基于 HTTP 的組件系統HTTP的組件系統包括客戶端、web服務器和代理。
客戶端:user-agent瀏覽器,特殊比如是工程師使用的程序,以及Web開發人員調試應用程序。
Web服務端由Web Server來服務并提供客戶端所請求的文檔。每一個發送到服務器的請求,都會被服務器處理并返回一個消息,也就是response。
代理(Proxies)在瀏覽器和服務器之間,有很多計算機和其他設備轉發了HTTP消息。它們可能出現在傳輸層、網絡層和物理層上,對于HTTP應用層而言就是透明的。
有如下的一些作用:
緩存過濾(像防病毒掃描、家長控制)負載均衡認證(對不同的資源進行權限控制)日志管理HTTP 報文組成HTTP 有兩種類型的消息:
請求——由客戶端發送用來觸發一個服務器上的動作。響應——來自服務器端的應答。HTTP消息由采用ASCII編碼的多行文本構成的。在HTTP/1.1以及更早的版本中,這些消息通過連接公開的發送。在HTTP2.0中,消息被分到了多個HTTP幀中。通過配置文件(用于代理服務器或者服務器),API(用于瀏覽器)或者其他接口提供HTTP消息。
典型的 HTTP 會話建立連接 在客戶端-服務器協議中,連接是由客戶端發起建立的。在HTTP?中打開連接意味著在底層傳輸層啟動連接,通常是TCP?。使用TCP?時,HTTP?服務器的默認端口號是80?,另外還有8000?和8080也很常用。發送客戶端請求。服務器響應請求。HTTP 請求和響應HTTP 請求和響應都包括起始行(start line)、請求頭(HTTP Headers)、空行(empty line)以及body部分,如下圖所示:
起始行。請求的起始行:請求方法、請求Path和HTTP版本號 響應的起始行:HTTP版本號、響應狀態碼以及狀態文本描述。
下面詳細說下請求Path,請求路徑(Path)有以下幾種:
1)一個絕對路徑,末尾跟上一個 " ? " 和查詢字符串。這是最常見的形式,稱為 原始形式 (origin form),被GET,POST,HEAD和OPTIONS方法所使用。
POST / HTTP/1.1GET /background.png HTTP/1.0HEAD /test.html?query=alibaba HTTP/1.1OPTIONS /anypage.html HTTP/1.0
2)一個完整的URL。主要在使用GET方法連接到代理的時候使用。
GET http://developer.mozilla.org/en-US/docs/Web/HTTP/Messages HTTP/1.1
3)由域名和可選端口(以":"為前綴)組成的URL的authority component,稱為authority form。僅在使用CONNECT建立HTTP隧道時才使用。
CONNECT developer.mozilla.org:80 HTTP/1.1
4)星號形式 (asterisk form),一個簡單的星號("*"),配合OPTIONS方法使用,代表整個服務器。
OPTIONS * HTTP/1.1Headers?請求頭或者響應頭。詳見下面的首部。不區分大小寫的字符串,緊跟著的冒號 (":") 和一個結構取決于header的值??招?。很多人容易忽略。Body。
請求Body部分:有些請求將數據發送到服務器以便更新數據:常見的的情況是POST請求(包含HTML表單數據)。請求報文的Body一般為兩類。一類是通過Content-Type和Content-Length定義的單文件body。另外一類是由多Body組成,通常是和HTML Form聯系在一起的。兩者的不同表現在于Content-Type的值。
1)Content-Type —— application/x-www-form-urlencoded對于application/x-www-form-urlencoded格式的表單內容,有以下特點:
I.其中的數據會被編碼成以&分隔的鍵值對。
II.字符以URL編碼方式編碼。
// 轉換過程: {a: 1, b: 2} -> a=1&b=2 -> 如下(最終形式)"a%3D1%26b%3D2"
2)Content-Type —— multipart/form-data。
請求頭中的Content-Type字段會包含boundary,且boundary的值有瀏覽器默認指定。例:Content-Type: multipart/form-data;boundary=----WebkitFormBoundaryRRJKeWfHPGrS4LKe。
數據會分為多個部分,每兩個部分之間通過分隔符來分隔,每部分表述均有HTTP頭部描述子包體,如Content-Type,在最后的分隔符會加上--表示結束。
Content-Disposition: form-data;name="data1";Content-Type: text/plaindata1----WebkitFormBoundaryRRJKeWfHPGrS4LKeContent-Disposition: form-data;name="data2";Content-Type: text/plaindata2----WebkitFormBoundaryRRJKeWfHPGrS4LKe--
響應Body部分:
1)由已知長度的單個文件組成。該類型body由兩個header定義:Content-Type和Content-Length。
2)由未知長度的單個文件組成,通過將Transfer-Encoding設置為chunked來使用chunks編碼。
關于Content-Length在下面HTTP 1.0中會提到,這個是HTTP 1.0中新增的非常重要的頭部。
方法安全方法:HTTP定義了一組被稱為安全方法的方法。GET方法和HEAD方法都被認為是安全的,這意味著GET方法和HEAD方法都不會產生什么動作 ——HTTP請求不會再服務端產生什么結果,但這并不意味著什么動作都沒發生,其實這更多的是web開發者決定的。
GET:請求服務器發送某個資源。HEAD:跟GET方法類似,但服務器在響應中只返回了首部。不會返回實體的主體部分。PUT:向服務器中寫入文檔。語義:用請求的主體部分來創建一個由所請求的URL命名的新文檔。POST:用來向服務器中輸入數據的。通常我們提交表單數據給服務器?!綪OST用于向服務器發送數據,PUT方法用于向服務器上的資源(例如文件)中存儲數據】。TRACE:主要用于診斷。實現沿通向目標資源的路徑的消息環回(loop-back)測試 ,提供了一種實用的debug機制。OPTIONS:請求WEB服務器告知其支持的各種功能??梢栽儐柗掌髦С帜男┓椒??;蛘哚槍δ承┨厥赓Y源支持哪些方法。DELETE:請求服務器刪除請求URL中指定的的資源。GET 和 POST 的區別首先要了解下副作用和冪等的概念,副作用指的是對服務器端資源做修改。冪等指發送M和N次請求(兩者不相同且都大于 1),服務器上資源的狀態一致。應用場景上,get是無副作用的,冪等的。post 主要是有副作用的,不冪等的情況。
技術上有以下的區分:
緩存:Get請求能緩存,Post請求不能。安全:Get請求沒有Post請求那么安全,因為請求都在URL中。且會被瀏覽器保存歷史紀錄。POST放在請求體中,更加安全。限制:URL有長度限制,會干預Get請求,這個是瀏覽器決定的。編碼:GET請求只能進行URL編碼,只能接收ASCII字符,而POST沒有限制。POST支持更多的編碼類型,而且不對數據類型做限制。從TCP的角度,GET請求會把請求報文一次性發出去,而POST會分為兩個TCP數據包,首先發header部分,如果服務器響應100(continue), 然后發body部分。(火狐瀏覽器除外,它的POST請求只發一個TCP包)。狀態碼?100~199——信息性狀態碼101 Switching Protocols。在HTTP升級為WebSocket的時候,如果服務器同意變更,就會發送狀態碼 101。
200~299——成功狀態碼200 OK,表示從客戶端發來的請求在服務器端被正確處理。
204 No content,表示請求成功,但響應報文不含實體的主體部分。
205 Reset Content,表示請求成功,但響應報文不含實體的主體部分,但是與 204 響應不同在于要求請求方重置內容。
206 Partial Content,進行范圍請求。
300~399——重定向狀態碼301 moved permanently,永久性重定向,表示資源已被分配了新的 URL。
302 found,臨時性重定向,表示資源臨時被分配了新的 URL。
303 see other,表示資源存在著另一個 URL,應使用 GET 方法獲取資源。
304 not modified,表示服務器允許訪問資源,但因發生請求未滿足條件的情況。
307 temporary redirect,臨時重定向,和302含義類似,但是期望客戶端保持請求方法不變向新的地址發出請求。
400~499——客戶端錯誤狀態碼400 bad request,請求報文存在語法錯誤。
401 unauthorized,表示發送的請求需要有通過 HTTP 認證的認證信息。
403 forbidden,表示對請求資源的訪問被服務器拒絕。
404 not found,表示在服務器上沒有找到請求的資源。
500~599——服務器錯誤狀態碼500 internal sever error,表示服務器端在執行請求時發生了錯誤。
501 Not Implemented,表示服務器不支持當前請求所需要的某個功能。
503 service unavailable,表明服務器暫時處于超負載或正在停機維護,無法處理請求。
首部HTTP Headers
1.通用首部(General headers)同時適用于請求和響應消息,但與最終消息主體中傳輸的數據無關的消息頭。如Date。
2.請求首部(Request headers)包含更多有關要獲取的資源或客戶端本身信息的消息頭。如 User-Agent。
3.響應首部(Response headers)包含有關響應的補充信息。
4.實體首部(Entity headers)含有關實體主體的更多信息,比如主體長(Content-Length)度或其MIME類型。如Accept-Ranges。
詳細的Header見HTTP Headers 集合[2]。
HTTP 的前世今生HTTP(HyperText Transfer Protocol)是萬維網(World Wide Web)的基礎協議。Tim Berners-Lee博士和他的團隊在1989-1991年間創造出它?!綡TTP、網絡瀏覽器、服務器】。
在 1991 年發布了HTTP 0.9版,在 1996 年發布 1.0 版,1997 年是 1.1 版,1.1 版也是到今天為止傳輸最廣泛的版本。2015 年發布了 2.0 版,其極大的優化了HTTP/1.1的性能和安全性,而 2018 年發布的 3.0 版,繼續優化HTTP/2,激進地使用UDP取代TCP協議,目前,HTTP/3在 2019 年 9 月 26 日 被Chrome,Firefox,和Cloudflare支持。
HTTP 0.9單行協議,請求由單行指令構成。以唯一可用的方法GET開頭。后面跟的是目標資源的路徑。
GET /mypage.html
響應:只包括響應文檔本身。
這是一個非常簡單的HTML頁面沒有響應頭,只傳輸HTML文件沒有狀態碼HTTP 1.0
RFC 1945[3]提出了HTTP1.0,構建更好可拓展性。
協議版本信息會隨著每個請求發送。響應狀態碼。引入了HTTP頭的概念,無論是請求還是拓展,允許傳輸元數據。使協議變得靈活,更加具有拓展性。Content-Type請求頭,具備了傳輸除純文本HTML文件以外其他類型文檔的能力 在響應中,Content-Type標頭告訴客戶端實際返回的內容的內容類型。媒體類型是一種標準。用來表示文檔、文件或者字節流的性質和格式。瀏覽器通常使用MIME(Multipurpose Internet Mail Extensions)類型來確定如何處理URL,因此Web服務器在響應頭中配置正確的MIME類型會非常的重要。如果配置不正確,可能會導致網站無法正常的工作。MIME的組成結構非常簡單;由類型與子類型兩個字符串中間用"/"分隔而組成。
HTTP從MIME type取了一部分來標記報文body部分的數據類型,這些類型體現在Content-Type這個字段,當然這是針對于發送端而言,接收端想要收到特定類型的數據,也可以用Accept字段。
這兩個字段的取值可以分為下面幾類:
- text:text/html, text/plain, text/css 等- image: image/gif, image/jpeg, image/png 等- audio/video: audio/mpeg, video/mp4 等- application: application/json, application/javascript, application/pdf, application/octet-stream
同時為了約定請求的數據和響應數據的壓縮方式、支持語言、字符集等,還提出了以下的Header。
1.壓縮方式:發送端:Content-Encoding(服務端告知客戶端,服務器對實體的主體部分的編碼方式) 和 接收端:Accept-Encoding(用戶代理支持的編碼方式),值有 gzip: 當今最流行的壓縮格式;deflate: 另外一種著名的壓縮格式;br: 一種專門為 HTTP 發明的壓縮算法。
2.支持語言:Content-Language和Accept-Language(用戶代理支持的自然語言集)。
3.字符集:發送端:Content-Type中,以charset屬性指定。接收端:Accept-Charset(用戶代理支持的字符集)。
// 發送端Content-Encoding: gzipContent-Language: zh-CN, zh, enContent-Type: text/html; charset=utf-8// 接收端Accept-Encoding: gzipAccept-Language: zh-CN, zh, enAccept-Charset: charset=utf-8
雖然 HTTP1.0在HTTP 0.9的基礎上改進了很多,但還是存在這不少的缺點。
HTTP/1.0版的主要缺點是,每個TCP連接只能發送一個請求。發送數據完畢,連接就關閉,如果還要請求其他資源,就必須再新建一個連接。TCP連接的新建成本很高,因為需要客戶端和服務器三次握手,并且開始時發送速率較慢(slow start)。
HTTP最早期的模型,也是 HTTP/1.0的默認模型,是短連接。每一個HTTP請求都由它自己獨立的連接完成;這意味著發起每一個HTTP請求之前都會有一次TCP握手,而且是連續不斷的。
HTTP 1.1HTTP/1.1在1997年1月以RFC 2068[4]文件發布。
HTTP 1.1消除了大量歧義內容并引入了多項技術:
連接可以復用。長連接:connection: keep-alive。HTTP 1.1支持長連接(PersistentConnection),在一個TCP連接上可以傳送多個HTTP請求和響應,減少了建立和關閉連接的消耗和延遲,在HTTP1.1中默認開啟Connection:keep-alive,一定程度上彌補了HTTP1.0每次請求都要創建連接的缺點。增加了管道化技術(HTTP Pipelinling),允許在第一個應答被完全發送完成之前就發送第二個請求,以降低通信延遲。復用同一個TCP連接期間,即便是通過管道同時發送了多個請求,服務端也是按請求的順序依次給出響應的;而客戶端在未收到之前所發出所有請求的響應之前,將會阻塞后面的請求(排隊等待),這稱為"隊頭堵塞"(Head-of-line blocking)。支持響應分塊,分塊編碼傳輸:Transfer-Encoding: chunkedContent-length聲明本次響應的數據長度。keep-alive連接可以先后傳送多個響應,因此用Content-length來區分數據包是屬于哪一個響應。使用Content-Length字段的前提條件是,服務器發送響應之前,必須知道響應的數據長度。對于一些很耗時的動態操作來說,這意味著,服務器要等到所有操作完成,才能發送數據,顯然這樣的效率不高。更好的處理方法是,產生一塊數據,就發送一塊,采用"流模式"(Stream)取代"緩存模式"(Buffer)。因此,HTTP 1.1規定可以不使用Content-Length字段,而使用"分塊傳輸編碼"(Chunked Transfer Encoding)。只要請求或響應的頭信息有Transfer-Encoding: chunked字段,就表明body將可能由數量未定的多個數據塊組成。每個數據塊之前會有一行包含一個 16 進制數值,表示這個塊的長度;最后一個大小為 0 的塊,就表示本次響應的數據發送完了。引入額外的緩存控制機制。在HTTP1.0中主要使用header里的If-Modified-Since,Expires等來做為緩存判斷的標準,HTTP1.1則引入了更多的緩存控制策略例如Entity tag,If-None-Match,Cache-Control等更多可供選擇的緩存頭來控制緩存策略。Host頭。不同的域名配置同一個IP地址的服務器。Host是HTTP 1.1協議中新增的一個請求頭,主要用來實現虛擬主機技術。虛擬主機(virtual hosting)即共享主機(shared web hosting),可以利用虛擬技術把一臺完整的服務器分成若干個主機,因此可以在單一主機上運行多個網站或服務。
舉個栗子,有一臺ip地址為61.135.169.125的服務器,在這臺服務器上部署著谷歌、百度、淘寶的網站。為什么我們訪問https://www.google.com時,看到的是Google的首頁而不是百度或者淘寶的首頁?原因就是Host請求頭決定著訪問哪個虛擬主機。
HTTP 2.02015年,HTTP2.0面世。rfc7540[5]。
HTTP/2是二進制協議而不是文本協議。先來看幾個概念:幀:客戶端與服務器通過交換幀來通信,幀是基于這個新協議通信的最小單位。
消息:是指邏輯上的 HTTP 消息,比如請求、響應等,由一或多個幀組成。
流:流是連接中的一個虛擬信道,可以承載雙向的消息;每個流都有一個唯一的整數標識符。
HTTP 2.0中的幀將HTTP/1.x消息分成幀并嵌入到流 (stream) 中。數據幀和報頭幀分離,這將允許報頭壓縮。將多個流組合,這是一個被稱為多路復用 (multiplexing) 的過程,它允許更有效的底層TCP連接。
也就是說,流用來承載消息,消息又是有一個或多個幀組成。二進制傳輸的方式更加提升了傳輸性能。每個數據流都以消息的形式發送,而消息又由一個或多個幀組成。幀是流中的數據單位。
HTTP幀現在對Web開發人員是透明的。在HTTP/2中,這是一個在 HTTP/1.1和底層傳輸協議之間附加的步驟。Web開發人員不需要在其使用的API中做任何更改來利用HTTP幀;當瀏覽器和服務器都可用時,HTTP/2將被打開并使用。
這是一個復用協議。并行的請求能在同一個連接中處理,移除了HTTP/1.x中順序和阻塞的約束。多路復用允許同時通過單一的HTTP/2連接發起多重的請求-響應消息。之前我們提到,雖然HTTP 1.1有了長連接和管道化的技術,但是還是會存在 隊頭阻塞。而HTTP 2.0就解決了這個問題HTTP/2中新的二進制分幀層突破了這些限制,實現了完整的請求和響應復用:客戶端和服務器可以將HTTP消息分解為互不依賴的幀,然后交錯發送,最后再在另一端把它們重新組裝起來。
如上圖所示,快照捕捉了同一個連接內并行的多個數據流??蛻舳苏谙蚍掌鱾鬏斠粋€DATA幀(數據流 5),與此同時,服務器正向客戶端交錯發送數據流 1 和數據流 3 的一系列幀。因此,一個連接上同時有三個并行數據流。
將 HTTP 消息分解為獨立的幀,交錯發送,然后在另一端重新組裝是HTTP 2最重要的一項增強。事實上,這個機制會在整個網絡技術棧中引發一系列連鎖反應,從而帶來巨大的性能提升,讓我們可以:1.并行交錯地發送多個請求,請求之間互不影響。2.并行交錯地發送多個響應,響應之間互不干擾。3.使用一個連接并行發送多個請求和響應。4.消除不必要的延遲和提高現有網絡容量的利用率,從而減少頁面加載時間。5.不必再為繞過 HTTP/1.x 限制而做很多工作(比如精靈圖) ...
連接共享,即每一個request都是是用作連接共享機制的。一個request對應一個id,這樣一個連接上可以有多個request,每個連接的request可以隨機的混雜在一起,接收方可以根據request的id將request再歸屬到各自不同的服務端請求里面。
HTTP 1.1和HTTP 2.0的對比,可以參考這個網站 demo 演示[6]。
HTTP 1.1演示如下:
HTTP2.0演示如下:
壓縮了headers。HTTP1.x的header帶有大量信息,而且每次都要重復發送,就造成了性能的損耗。為了減少此開銷和提升性能,HTTP/2使用HPACK壓縮格式壓縮請求和響應標頭元數據,這種格式采用兩種簡單但是強大的技術:這種格式支持通過靜態霍夫曼代碼對傳輸的標頭字段進行編碼,從而減小了各個傳輸的大小。這種格式要求客戶端和服務器同時維護和更新一個包含之前見過的標頭字段的索引列表(換句話說,它可以建立一個共享的壓縮上下文),此列表隨后會用作參考,對之前傳輸的值進行有效編碼。服務端推送。其允許服務器在客戶端緩存中填充數據,通過一個叫服務器推送的機制來提前請求。服務器向客戶端推送資源無需客戶端明確地請求,服務端可以提前給客戶端推送必要的資源,這樣可以減少請求延遲時間,例如服務端可以主動把JS和CSS文件推送給客戶端,而不是等到HTML解析到資源時發送請求,這樣可以減少延遲時間大致過程如下圖所示:
如何升級你的 HTTP 版本使用HTTP/1.1和HTTP/2對于站點和應用來說是透明的。擁有一個最新的服務器和新點的瀏覽器進行交互就足夠了。只有一小部分群體需要做出改變,而且隨著陳舊的瀏覽器和服務器的更新,而不需Web開發者做什么,用的人自然就增加了。
HTTPSHTTPS也是通過HTTP協議進行傳輸信息,但是采用了TLS協議進行了加密。
對稱加密和非對稱加密對稱加密就是兩邊擁有相同的秘鑰,兩邊都知道如何將密文加密解密。但是因為傳輸數據都是走的網絡,如果將秘鑰通過網絡的方式傳遞的話,一旦秘鑰被截獲就沒有加密的意義的。
非對稱加密公鑰大家都知道,可以用公鑰加密數據。但解密數據必須使用私鑰,私鑰掌握在頒發公鑰的一方。首先服務端將公鑰發布出去,那么客戶端是知道公鑰的。然后客戶端創建一個秘鑰,并使用公鑰加密,發送給服務端。服務端接收到密文以后通過私鑰解密出正確的秘鑰。
TLS 握手過程TLS握手的過程采用的是非對稱加密
Client Hello: 客戶端發送一個隨機值(Random1)以及需要的協議和加密方式。Server Hello以及Certificate: 服務端收到客戶端的隨機值,自己也產生一個隨機值(Random2),并根據客戶端需求的協議和加密方式來使用對應的方式,并且發送自己的證書(如果需要驗證客戶端證書需要說明)。Certificate Verify: 客戶端收到服務端的證書并驗證是否有效,驗證通過會再生成一個隨機值(Random3),通過服務端證書的公鑰去加密這個隨機值并發送給服務端,如果服務端需要驗證客戶端證書的話會附帶證書。Server 生成 secret: 服務端收到加密過的隨機值并使用私鑰解密獲得第三個隨機值(Random3),這時候兩端都擁有了三個隨機值,可以通過這三個隨機值按照之前約定的加密方式生成密鑰,接下來的通信就可以通過該密鑰來加密解密。HTTP 緩存強緩存強緩存主要是由Cache-control和Expires兩個Header決定的。
Expires的值和頭里面的Date屬性的值來判斷是否緩存還有效。Expires是Web服務器響應消息頭字段,在響應http請求時告訴瀏覽器在過期時間前瀏覽器可以直接從瀏覽器緩存取數據,而無需再次請求。Expires的一個缺點就是,返回的到期時間是服務器端的時間,這是一個絕對的時間,這樣存在一個問題,如果客戶端的時間與服務器的時間相差很大(比如時鐘不同步,或者跨時區),那么誤差就很大。
Cache-Control指明當前資源的有效期,控制瀏覽器是否直接從瀏覽器緩存取數據還是重新發請求到服務器取數據。但是其設置的是一個相對時間。
指定過期時間:max-age是距離請求發起的時間的秒數,比如下面指的是距離發起請求 31536000S 內都可以命中強緩存。
Cache-Control: max-age=31536000
表示沒有緩存。
Cache-Control: no-store
有緩存但要重新驗證。
Cache-Control: no-cache
私有和公共緩存。
public表示響應可以被任何中間人(比如中間代理、CDN等緩存) 而private則表示該響應是專用于某單個用戶的,中間人不能緩存此響應,該響應只能應用于瀏覽器私有緩存中。
Cache-Control: privateCache-Control: public
驗證方式:以下表示一旦資源過期(比如已經超過max-age),在成功向原始服務器驗證之前,緩存不能用該資源響應后續請求。
Cache-Control: must-revalidate
Cache-control優先級比Expires優先級高。
以下是一個Cache-Control強緩存的過程:
首次請求,直接從 server 中獲取。其中會設置max-age=100。第二次請求,age=10,小于 100,則命中Cache,直接返回。第三次請求,age=110,大于 110。強緩存失效,就需要再次請求Server。協商緩存If-Modified-Since——Last-ModifiedLast-Modified表示本地文件最后修改日期,瀏覽器會在request header加上If-Modified-Since(上次返回的Last-Modified的值),詢問服務器在該日期后資源是否有更新,有更新的話就會將新的資源發送回來。
但是如果在本地打開緩存文件,就會造成Last-Modified被修改,所以在HTTP / 1.1出現了ETag。
If-none-match——ETagsEtag就像一個指紋,資源變化都會導致ETag變化,跟最后修改時間沒有關系,ETag可以保證每一個資源是唯一的。If-None-Match的header會將上次返回的Etag發送給服務器,詢問該資源的Etag是否有更新,有變動就會發送新的資源回來。
If-none-match、ETags優先級高于If-Modified-Since、Last-Modified。
第一次請求:
第二次請求相同網頁:
協商緩存,假如沒有改動的話,返回 304 ,改動了返回 200 資源
200:強緩存Expires/Cache-Control失效時,返回新的資源文件。200(from cache): 強緩Expires/Cache-Control兩者都存在,未過期,Cache-Control優先Expires時,瀏覽器從本地獲取資源成功。304(Not Modified):協商緩存Last-modified/Etag沒有過期時,服務端返回狀態碼304。現在的200(from cache)已經變成了disk cache(磁盤緩存)和memory cache(內存緩存)兩種
revving 技術上面提到HTTP緩存相關,但是很多有時候,我們希望上線之后需要更新線上資源。
web開發者發明了一種被Steve Souders稱之為revving的技術。不頻繁更新的文件會使用特定的命名方式:在URL后面(通常是文件名后面)會加上版本號。
弊端:更新了版本號,所有引用這些的資源的地方的版本號都要改變。
web開發者們通常會采用自動化構建工具在實際工作中完成這些瑣碎的工作。當低頻更新的資源(js/css)變動了,只用在高頻變動的資源文件(html)里做入口的改動。
CookiesHTTP Cookie(也叫Web Cookie或瀏覽器Cookie)是服務器發送到用戶瀏覽器并保存在本地的一小塊數據,它會在瀏覽器下次向同一服務器再發起請求時被攜帶并發送到服務器上。
創建 cookieSet-Cookie響應頭部和Cookie請求頭部。
Set-Cookie:
會話期Cookie是最簡單的Cookie:瀏覽器關閉之后它會被自動刪除,也就是說它僅在會話期內有效。會話期Cookie不需要指定過期時間(Expires)或者有效期(Max-Age)。需要注意的是,有些瀏覽器提供了會話恢復功能,這種情況下即使關閉了瀏覽器,會話期Cookie也會被保留下來,就好像瀏覽器從來沒有關閉一樣。
持久性Cookie和關閉瀏覽器便失效的會話期Cookie不同,持久性Cookie可以指定一個特定的過期時間(Expires)或有效期(Max-Age)。
Set-Cookie: id=a3fWa; Expires=Wed, 21 Oct 2015 07:28:00 GMT;Cookie的Secure和HttpOnly 標記
標記為Secure的Cookie只應通過被HTTPS協議加密過的請求發送給服務端。
標記為Secure的Cookie只應通過被HTTPS協議加密過的請求發送給服務端。但即便設置了Secure標記,敏感信息也不應該通過Cookie傳輸,因為Cookie有其固有的不安全性,Secure標記也無法提供確實的安全保障。
通過JavaScript的Document.cookieAPI是無法訪問帶有HttpOnly標記的cookie。這么做是為了避免跨域腳本攻擊(XSS)。
Set-Cookie: id=a3fWa; Expires=Wed, 21 Oct 2015 07:28:00 GMT; Secure; HttpOnlyCookie的作用域
Domain和Path標識定義了Cookie的作用域:即Cookie應該發送給哪些URL。
Domain標識指定了哪些主機可以接受Cookie。如果不指定,默認為當前的主機(不包含子域名)。如果指定了Domain,則一般包含子域名。
例如,如果設置Domain=mozilla.org,則Cookie也包含在子域名中(如developer.mozilla.org)。
Path標識指定了主機下的哪些路徑可以接受Cookie(該URL路徑必須存在于請求URL中)。以字符 %x2F ("/") 作為路徑分隔符,子路徑也會被匹配。
例如,設置Path=/docs,則以下地址都會匹配:
/docs/docs/Web//docs/Web/HTTPSameSite Cookies
SameSite Cookie允許服務器要求某個cookie在跨站請求時不會被發送,從而可以阻止跨站請求偽造攻擊。
None瀏覽器會在同站請求、跨站請求下繼續發送cookies,不區分大小寫?!九f版本chrome默認Chrome 80版本之前】。
Strict瀏覽器將只在訪問相同站點時發送cookie。
Lax將會為一些跨站子請求保留,如圖片加載或者frames的調用,但只有當用戶從外部站點導航到URL時才會發送。如link鏈接:
Set-Cookie: key=value; SameSite=Strict
None Strict Lax
在新版本的瀏覽器(Chrome 80之后)中,SameSite的默認屬性是SameSite=Lax。換句話說,當Cookie沒有設置SameSite屬性時,將會視作SameSite屬性被設置為Lax—— 這意味著Cookies將不會在當前用戶使用時被自動發送。如果想要指定Cookies在同站、跨站請求都被發送,那么需要明確指定SameSite為None。因為這一點,我們需要好好排查舊系統是否明確指定SameSite,以及推薦新系統明確指定SameSite,以兼容新舊版本Chrome
更多cookie相關,可以查看我之前總結的一篇關于cookie的文章前端須知的 Cookie 知識小結[7]
HTTP訪問控制(CORS)跨域資源共享(CORS)是一種機制,它使用額外的HTTP頭告訴瀏覽器,讓運行在一個origin(domain) 上的web應用被準許訪問來自不同源服務器上的指定的資源
跨域資源共享標準新增了一組HTTP首部字段,允許服務器聲明哪些源站通過瀏覽器有權限訪問哪些資源。
簡單請求簡單請求(不會觸發CORS的預檢請求)需要同時滿足以下三點:
方法是GET/HEAD/POST之一。Content-Type的值僅限text/plain、multipart/form-data、application/x-www-form-urlencoded三者之一。HTTP頭部不能超過以下字段:Accept、Accept-Language、Content-LanguageContent-Type(需要注意額外的限制)DPR、Downlink、Save-Data、Viewport-Width、Width。以下為一個簡單請求的請求報文以及響應報文:
簡化以下:
請求首部字段Origin表明該請求來源于http://foo.example。
本例中,服務端返回的Access-Control-Allow-Origin: *表明,該資源可以被任意外域訪問。如果服務端僅允許來自http://foo.example的訪問,該首部字段的內容如下:
Access-Control-Allow-Origin: http://foo.example
Access-Control-Allow-Origin應當為 * 或者包含由Origin首部字段所指明的域名。
預檢請求規范要求,對那些可能對服務器數據產生副作用的HTTP請求方法。瀏覽器必須首先使用OPTIONS方法發起一個預檢請求(preflight request),從而獲知服務端是否允許該跨域請求。
服務器確認允許之后,才發起實際的HTTP請求。在預檢請求的返回中,服務器端也可以通知客戶端,是否需要攜帶身份憑證(包括Cookies和HTTP認證相關數據)
預檢請求中同時攜帶了下面兩個首部字段:
Access-Control-Request-Method: POSTAccess-Control-Request-Headers: X-PINGOTHER, Content-Type
首部字段Access-Control-Request-Method告知服務器,實際請求將使用POST方法。首部字段Access-Control-Request-Headers告知服務器,實際請求將攜帶兩個自定義請求首部字段:X-PINGOTHER與Content-Type。服務器據此決定,該實際請求是否被允許。
預檢請求的響應中,包括了以下幾個字段
Access-Control-Allow-Origin: http://foo.example// 表明服務器允許客戶端使用 POST, GET 和 OPTIONS 方法發起請求Access-Control-Allow-Methods: POST, GET, OPTIONS// 表明服務器允許請求中攜帶字段 X-PINGOTHER 與 Content-TypeAccess-Control-Allow-Headers: X-PINGOTHER, Content-Type// 表明該響應的有效時間為 86400 秒,也就是 24 小時。在有效時間內,瀏覽器無須為同一請求再次發起預檢請求。Access-Control-Max-Age: 86400
HTTP 請求和響應 一般而言,對于跨域XMLHttpRequest或Fetch請求,瀏覽器不會發送身份憑證信息。如果要發送憑證信息,需要設置XMLHttpRequest的某個特殊標志位。比如說XMLHttpRequest的withCredentials標志設置為true,則可以發送cookie到服務端。
對于附帶身份憑證的請求,服務器不得設置Access-Control-Allow-Origin的值為“*”。這是因為請求的首部中攜帶了Cookie信息,如果Access-Control-Allow-Origin的值為“*”,請求將會失敗。而將Access-Control-Allow-Origin的值設置為http://foo.example,則請求將成功執行。
CORS涉及到的請求和響應頭如下:HTTP響應首部字段
Access-Control-Allow-Origin允許訪問該資源的外域URI。對于不需要攜帶身份憑證的請求,服務器可以指定該字段的值為通配符,表示允許來自所有域的請求。Access-Control-Expose-Headers頭讓服務器把允許瀏覽器訪問的頭放入白名單Access-Control-Max-Age頭指定了preflight請求的結果能夠被緩存多久Access-Control-Allow-Credentials頭指定了當瀏覽器的credentials設置為true時是否允許瀏覽器讀取response的內容。Access-Control-Allow-Methods首部字段用于預檢請求的響應。其指明了實際請求所允許使用的HTTP方法。Access-Control-Allow-Headers首部字段用于預檢請求的響應。其指明了實際請求中允許攜帶的首部字段。HTTP請求首部字段:
Origin首部字段表明預檢請求或實際請求的源站Access-Control-Request-Method首部字段用于預檢請求。其作用是,將實際請求所使用的 HTTP 方法告訴服務器。Access-Control-Request-Headers首部字段用于預檢請求。其作用是,將實際請求所攜帶的首部字段告訴服務器。參考MDN[8]HTTP的發展[9]HTTP概述[10]HTTP/2 簡介[11]緩存(二)——瀏覽器緩存機制:強緩存、協商緩存[12](建議精讀)HTTP靈魂之問,鞏固你的 HTTP 知識體系[13]參考資料
[1]RFC 2616:https://tools.ietf.org/html/rfc2616
[2]HTTP Headers 集合:https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers
[3]RFC 1945:https://tools.ietf.org/html/rfc1945
[4]RFC 2068:https://tools.ietf.org/html/rfc2068
[5]rfc7540:https://httpwg.org/specs/rfc7540.html
[6]網站 demo 演示:https://http2.akamai.com/demo
[7]前端須知的 Cookie 知識小結:https://juejin.im/post/6844903841909964813
[8]MDN:https://developer.mozilla.org/zh-CN/docs/Web/HTTP
[9]HTTP的發展 :https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Basics_of_HTTP/Evolution_of_HTTP
[10]HTTP概述:https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Overview
[11]HTTP/2 簡介:https://developers.google.com/web/fundamentals/performance/http2?hl=zh-cn
[12]緩存(二)——瀏覽器緩存機制:強緩存、協商緩存:https://github.com/amandakelake/blog/issues/41
[13](建議精讀)HTTP靈魂之問,鞏固你的 HTTP 知識體系:https://juejin.im/post/6844904100035821575#heading-62
X 關閉
X 關閉
- 1亞馬遜開始大規模推廣掌紋支付技術 顧客可使用“揮手付”結賬
- 2現代和起亞上半年出口20萬輛新能源汽車同比增長30.6%
- 3如何讓居民5分鐘使用到各種設施?沙特“線性城市”來了
- 4AMD實現連續8個季度的增長 季度營收首次突破60億美元利潤更是翻倍
- 5轉轉集團發布2022年二季度手機行情報告:二手市場“飄香”
- 6充電寶100Wh等于多少毫安?鐵路旅客禁止、限制攜帶和托運物品目錄
- 7好消息!京東與騰訊續簽三年戰略合作協議 加強技術創新與供應鏈服務
- 8名創優品擬通過香港IPO全球發售4100萬股 全球發售所得款項有什么用處?
- 9亞馬遜云科技成立量子網絡中心致力解決量子計算領域的挑戰
- 10京東綠色建材線上平臺上線 新增用戶70%來自下沉市場