1. http的發展史
在學習網路之前,了解它的歷史能夠幫助我們明白為何它會發展為如今這個樣子,引發探究網路的興趣,下面的這張圖片就展示了“互聯網”誕生至今的發展歷程,
2. http是什么?
HyperTextTransferProtocol 直譯為‘超文本傳輸協議'
-
超文本:指文字、圖片、視頻、音頻等的混合體,比如最熟悉的html, -
傳輸:http是一個“雙向協議”,傳輸的是請求方和回應方之間的資料,不限制請求方和回應方之間的角色,傳遞的程序中可以存在任意“中間人”, -
協議:協是兩個或多個參與者之間的交流,議是指對參與者之間的約定和規范,所以,http協議可以理解為作用在計算機之間,使用計算機能夠理解的語言確立計算機之間交流通信的規范,以及相關的各種控制和錯誤處理方式,
所以對與以上的問題可以有這樣的總結:http是一個在計算機世界里專門在兩點之間傳遞文字、圖片、音頻、視頻等超文本資料的約定和規范,
3. 與http相關的一些概念
瀏覽器(web Browser): 瀏覽器的本質是http中的請求方,使用http協議獲得網路上的各種資源,在HTTP協議里,瀏覽器的角色被稱為"User Agent"即用戶代理,意思是作為訪問者的”代理來發起HTTP請求,下圖是一些主流瀏覽器及其內核,
服務器(web Server): 硬體含義就是物理形式或“云”形式的機器,軟體含義的 Web 服務器就是提供 Web 服務的應用程式,通常會運行在硬體含義的服務器上,它利用強大的硬體能力回應海量的客戶端 HTTP 請求,回傳動態的資訊,常見的web服務器有Apache、Nginx,
CDN(Content Delivery Network): CDN是為了解決長距離網路訪問速度慢的問題而誕生的一種網路應用服務,全稱為“內容分發網路”,CDN最核心的原則是“就近訪問”,使用HTTP協議里的代理和快取技術,用戶在上網的時候不直接訪問原網站,而是訪問離他最近的一個CDN節點,節省了訪問程序中的時間成本,(負載均衡,安全防護,邊緣計算).
爬蟲(Crawler):“機器人”形式的用戶代理,是一種可以自動訪問Web資源的應用程式,
HTML(Hyper Text Markup Language): 超文本標記語言,用于描述超文本頁面,用標簽定義圖片、文字、排版布局,最終由瀏覽器渲染,
web Service: 由W3C定義的應用服務開發規范,使用client-server主從架構,是一個基于Web(HTTP)的服務架構技術,
WAF: 網路應用防火墻,位于Web服務器之前,專門檢測http流量,是防護web應用安全的技術,可以阻止SQL注入,跨站腳本攻擊,可以完全集成進Apache或Nginx,
TCP/IP: 一系列網路通信協議的統稱,其中最核心的是TCP和IP協議,其他的還有UDP,ICMP,ARP等,共同構成一個復雜但有層次的協議堆疊,IP(Internet Protocol)協議主要解決尋址和路由問題,以及如何在兩點之間傳輸資料包,TCP(Transmission Control Protoco)協議位于IP協議之上,意思是“傳輸控制協議”,基于IP協議提供可靠地、位元組流形式的通信,是HTTP協議實作的基礎,互聯網上的 HTTP 協議運行在 TCP/IP 上,HTTP 也就可以更準確地稱為“HTTP over TCP/IP”,
DNS(Domain Name System): 域名系統,用有意義的名字來作為 IP 地址的等價替代,在 DNS 中,“域名”(Domain Name)又稱為“主機名”(Host),域名用“.”分隔成多個單詞,級別從左到右逐級升高,最右邊的被稱為“頂級域名”,但想要使用 TCP/IP 協議來通信仍然要使用 IP 地址,所以需要把域名做一個轉換,“映射”到它的真實 IP,這就是所謂的“域名決議”,
URI/URL: URI(Uniform Resource Identifier)中文名稱是統一資源識別符號,DNS 和 IP 地址只是標記了互聯網上的主機,URI能夠唯一地標記互聯網上資源,URI 另一個更常用的表現形式是 URL(Uniform Resource Locator), 統一資源定位符,也就是我們俗稱的“網址”,它實際上是 URI 的一個子集,通常不會做嚴格的區分,
URI 主要有三個基本的部分構成:
-
協議名:即訪問該資源應當使用的協議 -
主機名:即互聯網上主機的標記,可以是域名或 IP 地址 -
路徑:即資源在主機上的位置,使用“/”分隔多級目錄
HTTPS: 全稱是“HTTP over SSL/TLS”,也就是運行在 SSL/TLS 協議上的 HTTP,它是一個負責加密通信的安全協議,建立在 TCP/IP 之上,所以也是個可靠的傳輸協議,可以被用作 HTTP 的下層,相當于“HTTP+SSL/TLS+TCP/IP”,
代理(Proxy): 是 HTTP 協議中請求方和應答方中間的一個環節,作為“中轉站”,既可以轉發客戶端的請求,也可以轉發服務器的應答,
代理有很多的種類,常見的有:
-
匿名代理:完全“隱匿”了被代理的機器,外界看到的只是代理服務器; -
透明代理:顧名思義,它在傳輸程序中是“透明開放”的,外界既知道代理,也知道客戶端; -
正向代理:靠近客戶端,代表客戶端向服務器發送請求; -
反向代理:靠近服務器端,代表服務器回應客戶端的請求;
4.網路的分層模型
網路分層模型層級是從下往上數的,一般我們比較常接觸到的是TCP/IP四層模型,也是比較早出現的分層模型,
-
第一層是鏈路層(link layer),負責在底層網路上發送原始資料包,作業在網卡這個層次,使用 MAC 地址來標記網路上的設備,所以有時候也叫 MAC 層,對應的是ISO模型的"資料鏈路層", -
第二層叫網路層(internet layer),IP協議就處在這一層,因為IP協議定義了"IP 地址"的概念,所以就可以在"鏈路層"的基礎上,用IP地址取代MAC地址,在這個網路里找設備時只要把IP 地址再翻譯成MAC地址就可以了,對應的是ISO模型的"網路層", -
第三層叫"傳輸層"(transport layer),這個層次協議的職責是保證資料在IP地址標記的兩點之間可靠地傳輸,是TCP協議和UDP協議作業的層次,對應的是ISO模型的"傳輸層", -
第四層叫"應用層"(application layer),由于下面的三層把基礎打得非常好,所以在這一層就"百花齊放"了,有各種面向具體應用的協議,例如 Telnet、SSH、FTP、SMTP 等等,當然還有我們的 HTTP, 對應的是ISO模型的"會話層","表示層","應用層",
利用TCP/IP協議族進行網路通信時,會通過分層順序與對方進行通信(發送端從應用層往下走,接收端從應用層往上走),
5.域名
域名是一個有層次的結構,是一串用“.”分隔的多個單詞,最右邊的被稱為“頂級域名”,然后是“二級域名”,層級關系向左依次降低,最左邊的是主機名,通常用來表明主機的用途,比如“www”表示提供萬維網服務、“mail”表示提供郵件服務,不過這也不是絕對的,
可以通過下面的例子了解一下協議 主機 域名之間的層次關系,域名就像人的名字一樣,名字的關鍵是要讓我們容易記憶,除了標識身份之外,域名還可以代替ip地址,
6.DNS
我們經常會使用域名訪問網站,但其實在網路查找的工程當中是使用ip定位資源的,域名必須決議為ip地址才可以正確的拿到資源,DNS就是用來將域名變為ip的協議,
DNS 的核心系統是一個三層的樹狀、分布式服務,基本對應域名的結構:
-
根域名服務器(Root DNS Server):管理頂級域名服務器,回傳"com","net","cn"等頂級域名服務器的 IP 地址 -
頂級域名服務器(Top-level DNS Server):管理各自域名下的權威域名服務器,比如 cn 頂級域名服務器可以回傳 123.cn域名服務器的 IP 地址; -
權威域名服務器(Authoritative DNS Server):管理自己域名下主機的 IP 地址,比如 123.cn 權威域名服務器可以回傳 www.123.cn 的 IP 地址,
雖然DNS的服務,遍布全球,服務能力也很厲害,但是全世界的網民都在使用這個服務,也會對服務器造成很大的壓力,在核心 DNS 系統之外,還有兩種手段用來減輕域名決議的壓力,并且能夠更快地獲取結果,基本思路就是“快取”,
DNS的決議結果可以保存在大公司自己的DNS服務器里,或者作業系統快取、hosts 檔案當中,很多域名決議的作業就都不用請求根DNS服務器了,直接在本地或本機就能解決,不僅方便了用戶,也減輕了各級 DNS 服務器的壓力,效率就大大提升了,
基于域名和DNS服務器,我們可以實作重定向,因為域名代替了ip地址,所以可以對外域名不變,而主機IP可以任意變動,當主機有情況需要下線、遷移時,可以更改 DNS 記錄,讓域名指向其他的機器,
我們應該都聽說過負載均衡吧,DNS在域名決議階段就可以進行負載均衡的操作,
-
第一種方式,因為域名決議可以回傳多個 IP 地址,所以一個域名可以對應多臺主機,客戶端收到多個 IP 地址后,就可以自己使用輪詢演算法依次向服務器發起請求,實作負載均衡, -
第二種方式,域名決議可以配置內部的策略,回傳離客戶端最近的主機,或者回傳當前服務質量最好的主機,這樣在 DNS 端把請求分發到不同的服務器,實作負載均衡,
7.HTTP/1.X
前面我們說了HTTP就是“超文本傳輸協議”,是一個在計算機世界里專門在兩點之間傳遞文字、圖片、音頻、視頻等超文本資料的約定和規范,在學習過網路的層次模型之后我們又了解了HTTP是一個應用層的協議,在這個環節我們開始正式深入HTTP的世界(基于http/1.1),
HTTP報文
HTTP 協議的請求報文和回應報文的結構基本相同,由三大部分組成:
-
起始行(start line):描述請求或回應的基本資訊; -
頭部欄位集合(header):使用 key-value 形式更詳細地說明報文; -
訊息正文(entity):實際傳輸的資料,它不一定是純文本,可以是圖片、視頻等二進制資料,
請求行
請求行一般用來描述客戶端要怎樣操作服務端的資源,一般由三個部分組成,通常使用空格(space)來分隔,最后要用 CRLF 換行表示結束,
狀態行
狀態行一般用來描述服務端對于客戶端的請求回復的狀態,一般也是由三個部分組成,
頭部欄位
請求行或狀態行再加上頭部欄位集合就構成了 HTTP 報文里完整的請求頭或回應頭,除了起始行以外,請求頭和回應頭的結構基本相同,HTTP 頭欄位非常靈活,不僅可以使用標準里的 Host、Connection 等已有頭,也可以任意添加自定義頭,不過使用頭欄位需要注意下面幾點:
-
欄位名不區分大小寫,例如“Host”也可以寫成“host”,但首字母大寫的可讀性更好;
-
欄位名里不允許出現空格,可以使用連字符“-”,但不能使用下劃線“_”,例如,“test-name”是合法的欄位名,而“test name”“test_name”是不正確的欄位名;
-
欄位名后面必須緊接著“:”,不能有空格,而“:”后的欄位值前可以有多個空格;
-
欄位的順序是沒有意義的,可以任意排列不影響語意;
-
欄位原則上不能重復,除非這個欄位本身的語意允許,例如 Set-Cookie,
HTTP請求方法
目前 HTTP/1.1 規定了八種方法,單詞都必須是大寫的形式,下面就來看看這些方法:
-
GET:獲取資源,可以理解為讀取或者下載資料; -
HEAD:獲取資源的元資訊; -
POST:向資源提交資料,相當于寫入或上傳資料; -
PUT:類似 POST; -
DELETE:洗掉資源; -
CONNECT:建立特殊的連接隧道; -
OPTIONS:列出可對資源實行的方法; -
TRACE:追蹤請求 - 回應的傳輸路徑,
這幾個是我們比較常用的方法,有必要好好學習一下,
-
GET和HEAD
-
GET適用于向服務器請求資源,一般將資料攜帶于url上, -
HEAD類似于簡化版的GET請求,服務端收到HEAD請求時只回傳回應頭并且回應頭與GET完全一致 -
POST和PUT
-
POST 適用于向服務端發送資料,將資料攜帶在body當中,通常表示的是“create”的含義 -
PUT 類似于POST方法,也可以向服務器提交資料,是“update”的含義, -
GET和POST的區別
在這里特別容易被問到的問題是GET和POST的區別,我也想在這塊詳細的寫一下,以下是基于我個人的理解
1. 大小: GET通常將資料帶在URL當中而POST將資料放在body里(是RFC在語意上的要求,語法上GET也可以使用body傳輸資料而POST同樣可以把引數放在URL里),因此由于瀏覽器對于URL長度的限制,GET請求能攜帶的資料大小一般不超過2KB,值得一提Chrome瀏覽器對URL的長度限制已經增加到2MB,但是我們考慮到兼容性,URL的長度應該以最大限制的最小標準為主(IE瀏覽器限制為2KB),除了瀏覽器的限制,還應該考慮到服務端的限制,
2. 安全: 安全是指請求的方法是否會對服務器當中的資源造成影響,因為GET方法是只讀的,只要服務器沒有“曲解”客戶端的請求,服務端上的資料就是安全的,而POST會對服務端的資料進行“增刪改”的操作,因此是不安全的,
3. 冪等: 冪等的意思是說多次重復執行操作,產生的效果是否相同,顯然因為GET方法只對服務器上的資源做只讀操作,因此是冪等的,POST在RFC中的定義是“新增或提交資料”,多次提交資料會創建多個資源,所以不是冪等的(而 PUT 是“替換或更新資料”,多次更新一個資源,所以是冪等的),
4. 快取: 就是說這個方法的可快取性,絕大多數的瀏覽器的實作里僅僅支持GET快取,因為GET因為是讀取,就可以對GET請求的資料做快取,而POST不冪等也就意味著不能隨意多次執行,因此也就不能快取,
URI是什么
URI,也就是統一資源識別符號(Uniform Resource Identifier),因為它經常出現在瀏覽器的地址欄里,所以俗稱為“網路地址”,簡稱“網址”,URI 不完全等同于網址,它包含有 URL 和 URN 兩個部分,在 HTTP 世界里用的網址實際上是 URL——統一資源定位符(Uniform Resource Locator),但因為 URL 實在是太普及了,所以常常把這兩者簡單地視為相等,
URI 本質上是一個字串,這個字串的作用是唯一地標記資源的位置或者名字,
上面這個圖片就是一個完整的URI,下面詳細拆解一下它的結構,
scheme 協議名,表示資源應該使用哪種協議來訪問,最常見的當然就是“http”了,表示使用 HTTP 協議,另外還有“https”,表示使用經過加密、安全的 HTTPS 協議,此外還有其他不是很常見的 scheme,例如 ftp、ldap、file、news 等,
:// 分隔符,在 scheme 之后,必須是三個特定的字符“://”,它把 scheme 和后面的部分分離開,沒有特定的意義,
user:passwd@ 身份資訊,表示登錄主機時的用戶名和密碼,但現在已經不推薦使用這種形式了,因為它把敏感資訊以明文形式暴露出來,存在嚴重的安全隱患,
host:port 主機名,表示資源所在的主機名,通常的形式是“host:port”,即主機名加埠號,
path 路徑,表示資源所在位置,采用了類似檔案系統“目錄”的表示方式,通常以‘/’開始
query 查詢引數,用一個“?”開始,但不包含“?”,表示對資源附加的額外要求,path是多個“key=value”的字串,這些字串用字符“&”連接,瀏覽器和服務器都可以按照這個格式把長串的查詢引數決議成可理解的字典或關聯陣列形式,
#fragment 片段識別符號,它是 URI 所定位的資源內部的一個“錨點”,瀏覽器可以在獲取資源后直接跳轉到它指示的位置,但片段識別符號僅能由瀏覽器這樣的客戶端使用,服務器是看不到的,
在 URI 里只能使用 ASCII 碼,對于 ASCII 碼以外的字符集和特殊字符做一個特殊的操作,把它們轉換成與 URI 語意不沖突的形式,這在 RFC 規范里稱為“escape”和“unescape”,俗稱“轉義”,URI 轉義的規則有點“簡單粗暴”,直接把非 ASCII 碼或特殊字符轉換成十六進制位元組值,然后前面再加上一個“%”,
狀態碼
在HTTP報文部分我們說了HTTP的狀態行,我們在這個部分就來看看狀態行中的狀態碼,
狀態碼是一個十進制的數字,RFC 標準把狀態碼分成了五類,用數字的第一位表示分類,而 0 ~ 99 不用,這樣狀態碼的實際可用范圍就變成了 100~599,這五類的具體含義是:
-
1××:提示資訊,表示目前是協議處理的中間狀態,還需要后續的操作; -
2××:成功,報文已經收到并被正確處理; -
3××:重定向,資源位置發生變動,需要客戶端重新發送請求; -
4××:客戶端錯誤,請求報文有誤,服務器無法處理; -
5××:服務器錯誤,服務器在處理請求時內部發生了錯誤,
1××
1×× 類狀態碼屬于提示資訊,是協議處理的中間狀態,實際能夠用到的時候很少,
"100 Continue"因該是比較常接觸到的,會在POST請求發送大檔案給服務器時詢問服務器是否能夠接受時使用,需要帶上請求頭Expect: 100-continue
,這個程序也就是我們常說的POST發送兩個TCP包給服務器
的說法的來源,不過客戶端不需要一直等待服務端的回應,在一定時間內沒有收到否定的回答還是會將資料主體發送給服務器,
2××
2×× 類狀態碼表示服務器收到并成功處理了客戶端的請求,這也是客戶端最愿意看到的狀態碼,
“200 OK”是最常見的成功狀態碼,表示一切正常,服務器如客戶端所期望的那樣回傳了處理結果,如果是非 HEAD 請求,通常在回應頭后都會有 body 資料,
“204 No Content”是另一個很常見的成功狀態碼,它的含義與“200 OK”基本相同,但回應頭后沒有 body 資料,所以對于 Web 服務器來說,正確地區分 200 和 204 是很必要的,
“206 Partial Content”是 HTTP 分塊下載或斷點續傳的基礎,在客戶端發送“范圍請求”、要求獲取資源的部分資料時出現,它與 200 一樣,也是服務器成功處理了請求,但 body 里的資料不是資源的全部,而是其中的一部分,狀態碼 206 通常還會伴隨著頭欄位Content-Range
,表示回應報文里 body 資料的具體范圍,供客戶端確認,例如“Content-Range: bytes 0-99/2000”,意思是此次獲取的是總計 2000 個位元組的前 100 個位元組,
3××
3××類狀態碼表示客戶端請求的資源發生了變動,客戶端必須用新的 URI 重新發送請求獲取資源,也就是通常所說的“重定向”,包括著名的 301、302 跳轉,
“301 Moved Permanently” 俗稱“永久重定向”,含義是此次請求的資源已經不存在了,需要改用改用新的 URI 再次訪問,
“302 Found”,曾經的描述短語是“Moved Temporarily”,俗稱“臨時重定向”,意思是請求的資源還在,但需要暫時用另一個 URI 來訪問,
“304 Not Modified” 是一個比較有意思的狀態碼,它用于 If-Modified-Since 等條件請求,表示資源未修改,用于快取控制,它不具有通常的跳轉含義,但可以理解成“重定向已到快取的檔案”(即“快取重定向”),
4××
4××類狀態碼表示客戶端發送的請求報文有誤,服務器無法處理,它就是真正的“錯誤碼”含義了,
“400 Bad Request” 是一個通用的錯誤碼,表示請求報文有錯誤,只是一個籠統的錯誤,沒有明確含義的狀態碼,
“403 Forbidden” 實際上不是客戶端的請求出錯,而是表示服務器禁止訪問資源,
“404 Not Found” 原意是資源在本服務器上未找到,所以無法提供給客戶端,但現在已經被“用濫了”,只要服務器“不高興”就可以給出個 404,而我們也無從得知后面到底是真的未找到,還是有什么別的原因,某種程度上它比 403 還要令人討厭,
5××
5××類狀態碼表示客戶端請求報文正確,但服務器在處理時內部發生了錯誤,無法回傳應有的回應資料,是服務器端的“錯誤碼”,
“500 Internal Server Error” 與 400 類似,也是一個通用的錯誤碼,服務器究竟發生了什么錯誤我們是不知道的,不過對于服務器來說這應該算是好事,通常不應該把服務器內部的詳細資訊,例如出錯的函式呼叫堆疊告訴外界,雖然不利于除錯,但能夠防止黑客的窺探或者分析,
“501 Not Implemented” 表示客戶端請求的功能還不支持,這個錯誤碼比 500 要“溫和”一些,和“即將開業,敬請期待”的意思差不多,不過具體什么時候“開業”就不好說了,
“502 Bad Gateway” 通常是服務器作為網關或者代理時回傳的錯誤碼,表示服務器自身作業正常,訪問后端服務器時發生了錯誤,但具體的錯誤原因也是不知道的,
“503 Service Unavailable” 表示服務器當前很忙,暫時無法回應服務,我們上網時有時候遇到的“網路服務正忙,請稍后重試”的提示資訊就是狀態碼 503,503 是一個“臨時”的狀態,很可能過幾秒鐘后服務器就不那么忙了,可以繼續提供服務,所以 503 回應報文里通常還會有一個“Retry-After”欄位,指示客戶端可以在多久以后再次嘗試發送請求,
HTTP的特點
-
靈活可擴展:HTTP在誕生之初只規定了報文的基本格式,比如用空格分隔單詞,用換行分隔欄位,“header+body”等,報文里的各個組成部分都沒有做嚴格的語法語意限制,可以由開發者任意定制,而那些 RFC 檔案,實際上也可以理解為是對已有擴展的“承認和標準化”,實作了“從實踐中來,到實踐中去”的良性回圈, -
可靠傳輸: 因為 HTTP 協議是基于 TCP/IP 的,而 TCP 本身是一個“可靠”的傳輸協議,所以 HTTP 自然也就繼承了這個特性,能夠在請求方和應答方之間“可靠”地傳輸資料, -
應用層的協議: HTTP 憑借著可攜帶任意頭欄位和物體資料的報文結構,以及連接控制、快取代理等方便易用的特性,只要不太苛求性能,HTTP 幾乎可以傳遞一切東西,滿足各種需求,稱得上是一個“萬能”的協議, -
請求 - 應答:請求 - 應答模式是 HTTP 協議最根本的通信模型,通俗來講就是“一發一收”,請求 - 應答模式也明確了 HTTP 協議里通信雙方的定位,永遠是請求方先發起連接和請求,是主動的,而應答方只有在收到請求后才能答復,是被動的,如果沒有請求時不會有任何動作, -
無狀態: “狀態”其實就是客戶端或者服務器里保存的一些資料或者標志,記錄了通信程序中的一些變化資訊,HTTP在整個協議里沒有規定任何的“狀態”,但不要忘了 HTTP 是“靈活可擴展”的,雖然標準里沒有規定“狀態”,但完全能夠在協議的框架里給它“打個補丁”,增加這個特性(cookie), -
明文傳輸: “明文”意思就是協議里的報文(準確地說是 header 部分)不使用二進制資料,而是用簡單可閱讀的文本形式, -
不安全: 安全有很多的方面,明文只是“機密”方面的一個缺點,在“身份認證”和“完整性校驗”這兩方面 HTTP 也是欠缺的,
HTTP的物體資料
資料型別
Accept
在TCP/IP協議堆疊里,資料的傳輸都是Header+body的形式,在傳輸層協議中,不需要關心資料是什么,但在應用層必須要告訴上層資料的型別,否則上層就不知該如何處理,最早的HTTP協議中,并沒有附加的資料型別資訊,所有傳送的資料都被客戶程式解釋為HTML檔案,而為了支持多媒體資料型別,HTTP協議中就使用了附加在檔案之前的MIME(Multipurpose Internet Mail Extensions 多用途互聯網郵件擴展型別)指定的資料型別資訊來標識資料型別,MINE將資料分為七大類(video、image、application、text、audio、multipart、message),再以type/subtype的格式細分出其下的子類,例如我們常用到的text/html 、text/css 、image/jpeg 、 applaction/json等,
Accept-encoding
此外HTTP協議還制定了資料的壓縮格式:
-
gzip:GNU zip 壓縮格式,也是互聯網上最流行的壓縮格式; -
deflate:zlib(deflate)壓縮格式,流行程度僅次于 gzip; -
br:一種專門為 HTTP 優化的新壓縮演算法(Brotli),
Accept-Language
標記了客戶端可理解的自然語言,也允許用“,”做分隔符列出多個型別,例如:Accept-Language: zh-CN, zh, en
資料型別在請求頭中的表現
在 HTTP 協議里用 Accept、Accept-Encoding、Accept-Language 等請求頭欄位進行內容協商的時候,還可以用一種特殊的“q”引數表示權重來設定優先級,這里的“q”是“quality factor”的意思,權重的最大值是 1,最小值是 0.01,默認值是 1,如果值是 0 就表示拒絕,具體的形式是在資料型別或語言代碼后面加一個“;”,然后是“q=value”,服務器會在回應頭里多加一個 Vary 欄位,記錄服務器在內容協商時參考的請求頭欄位,
HTTP如何傳輸大檔案
-
資料壓縮
前面提到的accept-encoding
請求頭可以算是是一種傳輸大檔案的解決方式,服務器可以選擇一種瀏覽器支持的資料壓縮方式放進content-encoding
回應頭里,再把原資料壓縮后回傳給客戶端,缺點是這種方式只對文本有較好地壓縮率,對于圖片音頻等本身就已經高度壓縮的多媒體資料束手無策, -
分塊傳輸
在HTTP頭部表示為Transfer-Encoding: chunked
,指報文里的body部分不是一次性發過來的,而是分為許多chunked
分塊發送,Transfer-Encoding: chunked
和Content-Length
這兩個欄位是互斥的,也就是說回應報文里這兩個欄位不能同時出現,一個回應報文的傳輸要么是長度已知,要么是長度未知(chunked),這一點你一定要記住, -
范圍請求
如果想獲取某個大檔案其中的片段,分塊傳輸就沒辦法滿足這樣的需求,HTTP協議提出了范圍請求這樣的概念,允許客戶端只獲取檔案的某一部分,客戶端先發個HEAD請求看看服務器是否支持范圍請求,服務器必須在Accept-Ranges
回應頭中告知客戶端是否具有范圍請求的能力,請求頭Ranges
是HTTP范圍請求的專用欄位,值的格式是bytes=x-y
表示x ~ y
之間的范圍,服務端在收到Ranges
請求頭時,首先驗證x-y的范圍是否合法(x和y可以省略,省略x則表示從后往前,省略y則表示從前往后),其次計算讀取偏移量,回傳206狀態碼和所讀取的檔案 ,最后在回應頭加上Content-Range
表示實際回傳的偏移量和總數,格式為bytes x-y/length
,
范圍請求還支持在一個頭里定義多個x-y
,這種情況需要一種特殊的MIME型別multipart/byteranges
,表示報文是有多段組成,
HTTP連接管理
http的通信程序采取請求/應答模式,在http0.9/1.0時期,每次發起請求都需要建立連接->發送資料->斷開連接,由于整個請求的程序非常短暫,早起的http也稱為短鏈接
無鏈接的協議,由于TCP簡歷連接要經過三次握手四次揮手,整個程序需要3個RTT,而HTTP的一次簡單請求通常只需要2個RTT,那么被浪費掉的時間有60%,
Connection:keep-alive
HTTP1.1提出了長連接的概念,也就是Keep-alive
,在長連接上建立一次TCP連接可以發送多個HTTP請求,但因為連接是alive
的,如果一直不關閉,就會占用大量的服務器資源,導致服務無法及時回應真正的請求,所以我們也需要及時關閉連接,可以通過在客戶端請求頭添加Connection: close
欄位主動關閉連接,服務端通常不會主動關閉連接,但我們也可以通過設定時長、請求數等方式約定斷開連接的條件,
隊頭阻塞
基于請求-應答
模式的http協議,形成了串行的請求佇列(http1.1還提出了管道機制,即在同一個TCP連接上不用等待上一個請求的回應即可發出下個請求,不過客戶端還是按照正常順序接受回應,這種做法并沒帶來任何性能上的改善,所以默認保持關閉
),如果隊首的請求處于阻塞狀態,那么后面的請求也無法正常回應結果就是更長時間的性能浪費,
并發連接
和域名分片
是對隊頭阻塞的針對性優化策略,瀏覽器限制每個客戶端可以并發建立6~8個連接,又可以將多個域名指向同一個服務器,這樣實際的連接數量就更多了,是一種用數量解決質量的思路,
重定向
當我們在瀏覽器輸入一個url再按下回車,頁面跳轉到我們輸入的地址中,這種行為就是主動跳轉,瀏覽器還支持被動跳轉,也就是HTTP的重定向,
狀態碼
在前面了解過HTTP狀態碼,3XX
即表示為重定向,下面詳細介紹下各個狀態碼的含義,
301
指永久重定向,可能是域名下線,域名遷移等原因,原地址不再維護,此時瀏覽器在重定向的同時記錄重定向后的地址,下次訪問該域名就自動訪問新的URI了,
302
指臨時重定向,可能是服務器維護、臨時關閉等原因,臨時跳轉到新的地址上,此時瀏覽器不會記錄重定向的地址,認為原地址還是有效的,下次訪問時還是優先訪問原地址,
303
類似 302,但要求重定向后的請求改為 GET 方法,訪問一個結果頁面,避免 POST/PUT 重復操作,
307
類似 302,但重定向后請求里的方法和物體不允許變動,含義比 302 更明確,
308
類似 307,不允許重定向后的請求變動,但它是 301“永久重定向”的含義,
可以在地址欄輸入bing.com
,瀏覽器控制臺中的狀態如下圖所示:
客戶端是如何處理重定向的
在瀏覽器地址欄輸入bing.con我們可以看到,狀態碼如下圖所示:
我們瀏覽器收到回應之后根據回應頭中的Location欄位判斷重定向的地址,然后進行被動跳轉,
雖然重定向的用途很廣,但是隨之而來的也有跟多問題,
-
第一個問題是“性能損耗”,很明顯,重定向的機制決定了一個跳轉會有兩次 請求 - 應答
,比正常的訪問多了一次,雖然 301/302 報文很小,但大量的跳轉對服務器的影響也是不可忽視的,站內重定向可以長連接復用,站外重定向就要開兩個連接, -
第二的問題時回圈重定向,比如 A->B->C->A
,當我們訪問A時就會發生無限跳轉,所以HTTP協議特別規定,瀏覽器必須具有檢測“回圈跳轉”的能力,在發現這種情況時應當停止發送請求并給出錯誤提示,
cookie
HTTP 是“無狀態”的,這既是優點也是缺點,優點是服務器沒有狀態差異,可以很容易地組成集群,而缺點就是無法支持需要記錄狀態的事務操作,好在 HTTP 協議是可擴展的,后來發明的 Cookie 技術,給 HTTP 增加了“記憶能力”,
cookie同樣存在于HTTP頭部欄位里,服務端可以使用set-cookie
標識客戶端身份,客戶端則在請求時攜帶cookie
告訴服務端自己的資訊,cookie
欄位以key=value
的格式保存,瀏覽器在一個cookie
欄位里可以存放多對資料,用;
分割,
Cookie 主要用于以下三個方面:
-
會話狀態管理(如用戶登錄狀態、購物車、游戲分數或其它需要記錄的資訊) -
個性化設定(如用戶自定義設定、主題等) -
瀏覽器行為跟蹤(如跟蹤分析用戶行為等)
相關屬性
生存周期
Expires
俗稱“過期時間”,用的是絕對時間點,可以理解為“截止日期”(deadline),
Max-Age
用的是相對時間,單位是秒,瀏覽器用收到報文的時間點再加上 Max-Age,就可以得到失效的絕對時間,
Expires
和 Max-Age
可以同時出現,兩者的失效時間不一致時瀏覽器會優先采用Max-Age
計算失效期,如果服務器不設定Max-Age、Expries或者欄位值為0指不能快取cookie,但在會話期間是可用的,瀏覽器會話關閉之前可以用cookie記錄用戶的資訊,
作用域
Domain
和Path
指定了 Cookie 所屬的域名和路徑,瀏覽器在發送 Cookie 前會從 URI 中提取出 host 和 path 部分,對比 Cookie 的屬性,如果不滿足條件,就不會在請求頭里發送 Cookie,通常 Path 就用一個“/”或者直接省略,表示域名下的任意路徑都允許使用 Cookie,
安全性
HttpOnly
表示此 Cookie 只能通過瀏覽器 HTTP 協議傳輸,禁止其他方式訪問,這也是預防“跨站腳本”(XSS)攻擊的有效手段,
SameSite
可以防范“跨站請求偽造”(XSRF)攻擊,SameSite = strict
表示禁止cookie在跳轉鏈接時跨域傳輸,SameSite = lax
稍微寬松一點,允許在GET
、HEAD
等安全請求方式中跨域攜帶,默認值為none
,表示不限制cookie的攜帶和傳輸,
Secure
表示這個cookie僅能用HTTPS協議加密傳輸,明文的HTTP協議會禁止發送,但Cookie本身不是加密的,瀏覽器里還是以明文的形式存在,
HTTP快取控制
服務器的快取控制
瀏覽器在訪問頁面資源時首先會查找快取資料,如果沒有再發送請求,向服務器獲取資源;服務器回應請求,回傳資源,同時標記資源的有效期;瀏覽器快取資源,等待下次重用,這就是客戶端快取,
服務器標記資源有效期使用的頭欄位是Cache-Control
,里面的值max-age=xxx
就是資源的有效時間(與cookie的max-age不同,這里的max-age時間的計算起點是回應報文的創建時刻),
此外在回應報文里還可以用其他的值來更精確地指示瀏覽器應該如何使用快取:no-store
: 不允許快取,用于某些變化非常頻繁的資料,例如秒殺頁面;no-cache
: 可以快取,但在使用之前必須要去服務器驗證是否過期;must-revalidate
: 如果快取不過期就可以繼續使用,但過期了就必須去服務器驗證,
客戶端的快取控制
瀏覽器也可以發Cache-Control
,也就是說請求 - 應答
的雙方都可以用這個欄位進行快取控制,互相協商快取的使用策略,在瀏覽器前進、后退、重定向時cache-control就生效了,回應頭里有from disk cache
字樣,就說明瀏覽器未發送請求,而是直接使用了本地快取,
條件請求
瀏覽器在重繪頁面時相當于在請求頭中添加了Cache-Control:no-cache
,這樣在重繪頁面時,還是向服務端發送了請求,并沒有很好的利用到快取,所以HTTP協議又定義了一系列“If”開頭的“條件請求”欄位,專門用來檢查驗證資源是否過期,
條件請求一共有 5 個頭欄位,我們最常用的是if-Modified-Since
和If-None-Match
這兩個,需要第一次的回應報文預先提供Last-modified
(最后修改時間)和ETag
(資源唯一標識),然后第二次請求時就可以帶上快取里的原值,驗證資源是否是最新的,如果資源沒有變,服務器就回應一個“304 Not Modified”,表示快取依然有效,瀏覽器就可以更新一下有效期,然后放心大膽地使用快取了,
代理快取
代理服務器
代理服務器就是客戶端和服務端之間的中間商,在中間的位置轉發上游的請求和下游的回應,代理服務器在計算機領域有非常重要的功能
-
負載均衡:面向客戶端時屏蔽原服務器,代理服務器可以通過輪詢、哈希等演算法將流量分發,提高整體的性能, -
健康檢查:使用‘心跳’等機制監控服務器,保證服務器的可用性, -
安全防護:保護被代理服務端的IP和流量,防止網路攻擊或負載問題, -
加密卸載:對外和對內使用不同的加密策略,節省加密成本 -
內容快取:暫存/復位服務器的回應,
快取代理
HTTP的服務端快取主要由代理服務器來實作,代理服務器收到源服務器的回應之后將報文轉發給客戶端的同時也存入自己的cache里,下次再有相同的請求就可以直接發送304或者快取資料,節省源服務器的成本,
因為代理服務器既是服務端,又是客戶端
的特性,有一些特殊的cache-control
屬性:
-
服務端
private
: 表示只能客戶端快取,不允許代理服務器上快取,punlic
:表示完全公開,客戶端和代理服務器都可以快取,proxy-revalidate
:要求代理服務器快取過期后必須回源驗證,s-maxage
: 代理服務器快取的有效期no-transform
: 不允許代理服務器轉換資料格式,
-
客戶端
max-stale
: 如果代理上的快取過期了也可以接受,但不能過期太多,超過 x 秒也會不要,min-flash
: 表示快取少于x有效期就不要了,only-if-cached
:表示只接受代理快取的資料,不接受源服務器的回應,如果代理上沒有快取或者快取過期,就應該給客戶端回傳一個 504,
8. HTTPS
由于 HTTP 天生“明文”的特點,整個傳輸程序完全透明,任何人都能夠在鏈路中截獲、修改或者偽造請求 / 回應報文,資料不具有可信性,只有具有機密性、完整性、身份認證和不可否認性,我們才認為這個請求是安全的,HTTPS為HTTP增加了以上四個特性,
HTTPS實際上就指的是HTTP over TLS/SSl,是在原本的HTTP協議上加了一層TLS/SSL協議,
SSL/TLS
SSL 即安全套接層(Secure Sockets Layer),在 OSI 模型中處于第 5 層(會話層),由網景公司于 1994 年發明,SSL 發展到 v3 時已經證明了它自身是一個非常好的安全通信協議,于是在 1999 年它改名為 TLS(傳輸層安全, Transport Layer Security),目前應用的最廣泛的 TLS 是 1.2,而之前的協議(TLS1.1/1.0、SSLv3/v2)都已經被認為是不安全的,
機密性(基于TLS1.2)
SSL/TLS通過加密(encrypt)
來傳輸密文(cipher text)
保證資料傳輸的安全性,只有擁有密鑰(key)
的人才能夠通過解密(decrypt)
獲得明文(plain text/clear text)
,加密解密的操作程序就是加密演算法
,所以“密鑰”是一長串的數字,約定俗成的度量單位是“位”(bit),比如,說密鑰長度是 128,就是 16 位元組的二進制串,密鑰長度 1024,就是 128 位元組的二進制串,按照密鑰的使用方式,加密可以分為兩大類:對稱加密
和非對稱加密
,
對稱加密
顧名思義,加密解密都使用相同的密鑰就叫做對稱加密,TLS里目前常用的有 AES 和 ChaCha20,
AES
的意思是“高級加密標準”(Advanced Encryption Standard),密鑰長度可以是 128、192 或 256,它是 DES 演算法的替代者,安全強度很高,性能也很好,而且有的硬體還會做特殊優化,所以非常流行,是應用最廣泛的對稱加密演算法,
ChaCha20
是 Google 設計的另一種加密演算法,密鑰長度固定為 256 位,純軟體運行性能要超過 AES,曾經在移動客戶端上比較流行,但 ARMv8 之后也加入了 AES 硬體優化,所以現在不再具有明顯的優勢,
非對稱加密
對稱加密看上去很好的實作了機密性,但是還有一個問題就是如何安全的傳輸密鑰
,因為在加密演算法
中,只要擁有密鑰就可以解密,如果密鑰在傳輸程序中被竊取,也就無機密性可言,為了解決這個問題,又有了非對稱加密
演算法,他擁有兩個密鑰
,分別是公鑰(public key)
和私鑰(private key)
,公鑰
是公開的,而私鑰
是嚴格保密的,公鑰
和私鑰
有個特別的“單向”性
,雖然都可以用來加密解密,但公鑰
加密后只能用私鑰
解密,反過來,私鑰
加密后也只能用公鑰
解密,非對稱加密可以解決密鑰交換
的問題,網站秘密保管私鑰,在網上任意分發公鑰,你想要登錄網站只要用公鑰加密就行了,密文只能由私鑰持有者才能解密,而黑客因為沒有私鑰,所以就無法破解密文,
非對稱加密演算法的設計要比對稱演算法難得多,在 TLS 里只有很少的幾種,比如 DH、DSA、RSA、ECC 等,RSA
可能是其中最著名的一個,幾乎可以說是非對稱加密的代名詞,它的安全性基于“整數分解”的數學難題,使用兩個超大素數的乘積作為生成密鑰的材料,想要從公鑰推算出私鑰是非常困難的,
ECC
是非對稱加密里的“后起之秀”,它基于“橢圓曲線離散對數”的數學難題,使用特定的曲線方程和基點生成公鑰和私鑰,子演算法 ECDHE 用于密鑰交換,ECDSA 用于數字簽名,相對RSA,ECC在安全和性能上都有更明顯的優勢,160位的ECC相當于1024位的RSA,260位的ECC相當于2048位的RSA,
混合加密
雖然非對稱加密沒有密鑰交換
的難題,但因為它們都是基于復雜的數學難題,運算速度很慢,即使是 ECC 也要比 AES 差上好幾個數量級,所以目前TLS
使用混合加密
,使二者取長補短,既能高效加密解密,又能安全的進行資料傳輸,
在建立連接之初先使用非對稱加密的形式傳遞密鑰,然后用亂數產生對稱演算法使用的“會話密鑰”(session key),再用公鑰加密,因為會話密鑰很短,通常只有 16 位元組或 32 位元組,所以慢一點也無所謂,對方拿到密文后用私鑰解密,取出會話密鑰,這樣,雙方就實作了對稱密鑰的安全交換,后續就不再使用非對稱加密,全都使用對稱加密,
完整性
摘要演算法
實作完整性的手段主要是摘要演算法(Digest Algorithm)
,也就是常說的散列函式、哈希函式(Hash Function)
,可以把摘要演算法近似地理解成一種特殊的加密演算法,它能夠把任意長度的資料加密成固定長度、而且獨一無二的“摘要”字串,且不能從壓縮后的密文中推匯出原文,MD5(Message-Digest 5)、SHA-1(Secure Hash Algorithm 1
就是最常用的兩個摘要演算法,能夠生成 16 位元組和 20 位元組長度的數字摘要,但這兩個演算法的安全強度比較低,不夠安全,在 TLS 里已經被禁止使用了,目前TLS使用的是SLA-2
,摘要演算法保證了“數字摘要”和原文是完全等價的,所以,我們只要在原文后附上它的摘要,就能夠保證資料的完整性
,不過摘要演算法不具有機密性,所以真正的完整性還是需要建立在機密性之上,
身份認證&不可否認
數字簽名
數字簽名的原理其實很簡單,就是把公鑰私鑰的用法反過來,之前是公鑰加密、私鑰解密,現在是私鑰加密、公鑰解密,但又因為非對稱加密效率太低,所以私鑰只加密原文的摘要,這樣運算量就小的多,而且得到的數字簽名也很小,方便保管和傳輸,
數字證書和CA
因為公鑰
是任何人都可以發布的,所以我們需要引入第三方來保證公鑰
的可信度,這個“第三方”就是我們常說的 CA(Certificate Authority,證書認證機構),CA 對公鑰的簽名認證也是有格式的,要包含公鑰
的序列號、用途、頒發者、有效時間等等,把這些打成一個包再簽名,完整地證明公鑰關聯的各種資訊,形成“數字證書”(Certificate),小一點的 CA 可以讓大 CA 簽名認證,但鏈條的最后,也就是 Root CA,就只能自己證明自己了,這個就叫“自簽名證書”(Self-Signed Certificate)或者“根證書”(Root Certificate),你必須相信,否則整個證書信任鏈就走不下去了,
TLS1.2建立連接的程序
TLS協議的組成
記錄協議(Record Protocol):
規定了 TLS 收發資料的基本單位:記錄(record),所有的其他子協議都需要通過記錄協議發出,但多個記錄資料可以在一個 TCP 包里一次性發出,
警報協議(Alert Protocol):
的職責是向對方發出警報資訊,有點像是 HTTP 協議里的狀態碼,比如,protocol_version 就是不支持舊版本,bad_certificate 就是證書有問題,收到警報后另一方可以選擇繼續,也可以立即終止連接,
握手協議(Handshake Protocol):
是 TLS 里最復雜的子協議,要比 TCP 的 SYN/ACK 復雜的多,瀏覽器和服務器會在握手程序中協商 TLS 版本號、亂數、密碼套件等資訊,然后交換證書和密鑰引數,最終雙方協商得到會話密鑰,用于后續的混合加密系統,變更密碼規范協議(Change Cipher Spec Protocol):
是一個“通知”,告訴對方,后續的資料都將使用加密保護,那么反過來,在它之前,資料都是明文的,
基于ECDHE
的 TLS1.2
握手
TLS1.3
9. HTTP/2
HTTP1.X引入了Cookie解決了無狀態的問題、通過引入TLS/SSL解決了明文傳輸不安全的問題,那接下來HTTP2的發力點就放在性能層面了,Google首先發明了SPDY協議,隨后互聯網標準化組織IETF以SPDY 為基礎發布了HTTP2,HTTP2對于性能上的優化主要由以下幾點出發:1. 包頭過大 2. 隊頭阻塞 ,
性能優化
包頭過大(頭部壓縮)
在HTTP1.x時期,很多請求請求體和回應體的大小遠遠小于頭部欄位的大小,比如GET請求,301/302/204回應,而且很多頭部欄位是重復的,HTTP/1.x浪費了大量的帶寬在傳輸重復的頭欄位上,所以,HTTP/2 把“頭部壓縮”作為性能改進的一個重點,
HPACK
演算法是專門為壓縮 HTTP 頭部定制的演算法,與 gzip、zlib 等壓縮演算法不同,它是一個“有狀態”的演算法,需要客戶端和服務器各自維護一份“索引表”,壓縮和解壓縮就是查表和更新表的操作,為了方便管理和壓縮,HTTP/2 廢除了原有的起始行概念,把起始行里面的請求方法、URI、狀態碼等統一轉換成了頭欄位的形式, 為了與“真頭欄位”區分開來,這些“偽頭欄位”會在名字前加一個“:”,比如“:authority” “:method” “:status”,分別表示的是域名、請求方法和狀態碼,廢除了起始行里的版本號和錯誤原因短語,用索引號表示重復的字串,還釆用哈夫曼編碼來壓縮整數和字串,可以達到 50%~90% 的高壓縮率,
下面的這個表格列出了“靜態表”的一部分,這樣只要查表就可以知道欄位名和對應的值,比如數字“2”代表“GET”,數字“8”代表狀態碼 200,
新增的頭欄位或者值保存在動態表(Dynamic Table)
里,它添加在靜態表后面,結構相同,但會在編碼解碼的時候隨時更新,比如說,第一次發送請求時的“user-agent”欄位長是一百多個位元組,用哈夫曼壓縮編碼發送之后,客戶端和服務器都更新自己的動態表,添加一個新的索引號“65”,那么下一次發送的時候就不用再重復發那么多位元組了,只要用一個位元組發送編號就好,
隊頭阻塞(二進制分幀、流式傳輸)
基于請求-應答
模式的http協議存在隊頭阻塞的問題,前面提到的并發連接
和域名分片
都是犧牲數量解決質量的思路,而HTTP2采用了二進制分幀?流式傳輸的方式來解決這個問題,
二進制分幀
HTTP/2
把原來的Header+Body
的訊息“打散”為數個小片的二進制“幀”(Frame)
,用HEADER
幀存放頭資料、DATA
幀存放物體資料,
流式傳輸
HTTP/2
還定義了一個“流”(Stream)
的概念,它是二進制幀的雙向傳輸序列,同一個訊息往返的幀會分配一個唯一的流 ID,你可以把它想象成是一個虛擬的“資料流”,在里面流動的是一串有先后順序的資料幀,這些資料幀按照次序組裝起來就是HTTP/1
里的請求報文和回應報文,HTTP/2
可以在一個 TCP 連接上用“流”
同時發送多個“碎片化”
的訊息,這就是常說的“多路復用”( Multiplexing)
,多個往返通信都復用一個連接來處理,在“流”
的層面上看,訊息是一些有序的“幀”
序列,而在“連接”
的層面上看,訊息卻是亂序收發的“幀”
,多個請求 / 回應之
間沒有了順序關系,不需要排隊等待,也就不會再出現“隊頭阻塞”問題,降低了延遲,大幅度提高了連接的利用率,
幀開頭是幀長度
(不包含報文頭的9個位元組),默認上限是2^14,最大是2^24,也就是說 HTTP/2的幀通常不超過16K,最大是 16M,
后面的一個位元組是幀型別
,大致可以分成資料幀
和控制幀
兩類,HEADERS幀
和DATA幀
屬于資料幀
,存放的是 HTTP 報文,而 SETTINGS、PING、PRIORITY
等則是用來管理流的控制幀,
第 5 個位元組是非常重要的幀標志資訊
,可以保存 8 個標志位,攜帶簡單的控制資訊,常用的標志位有 END_HEADERS 表示頭資料結束,END_STREAM 表示單方向資料發送結束(即 EOS,End of Stream),
報文頭里最后 4 個位元組是流識別符號
,也就是幀所屬的“流”
,接收方使用它就可以從亂序的幀里識別出具有相同流 ID 的幀序列(在 HTTP/2 連接上,雖然幀是亂序收發的,但只要它們都擁有相同的流 ID,就都屬于一個流,而且在這個流里幀不是無序的,而是有著嚴格的先后順序,)
,按順序組裝起來就實作了虛擬的“流”,流識別符號雖然有 4 個位元組,但最高位被保留不用,所以只有 31 位可以使用,也就是說,流識別符號的上限是 2^31,大約是 21 億,
流
的特點
-
流是可并發的,一個 HTTP/2 連接上可以同時發出多個流傳輸資料,也就是并發多請求,實作“多路復用”; -
客戶端和服務器都可以創建流,雙方互不干擾; -
流是雙向的,一個流里面客戶端和服務器都可以發送或接收資料幀,也就是一個“請求 - 應答”來回; -
流之間沒有固定關系,彼此獨立,但流內部的幀是有嚴格順序的; -
流可以設定優先級,讓服務器優先處理,比如先傳 HTML/CSS,后傳圖片,優化用戶體驗; -
流 ID 不能重用,只能順序遞增,客戶端發起的 ID 是奇數,服務器端發起的 ID 是偶數; -
在流上發送“RST_STREAM”幀可以隨時終止流,取消接識訓發送; -
第 0 號流比較特殊,不能關閉,也不能發送資料幀,只能發送控制幀,用于流量控制,
協議堆疊
10.HTTP/3
HTTP/2
雖然使用“幀”
、“流”
、“多路復用”
,沒有了“隊頭阻塞”
,但這些手段都是在應用層里,而在 TCP 協議里,還是會發生“隊頭阻塞”,Google 在推 SPDY
的時候就已經意識到了這個問題,于是就又發明了一個新的QUIC
協議,讓 HTTP
跑在 QUIC
上而不是 TCP
上,而這個HTTP over QUIC
就是 HTTP
協議的下一個大版本,HTTP/3
,它在 HTTP/2 的基礎上又實作了質的飛躍,真正完美地解決了隊頭阻塞問題,
QUICK
QUIC 基于 UDP,而 UDP 是“無連接”的,不需要“握手”和“揮手”,所以天生就要比 TCP 快,QUIC 全面采用加密通信,它使用自己的幀“接管”了 TLS 里的“記錄”,握手訊息、警報訊息都不使用 TLS 記錄,直接封裝成 QUIC 的幀發送,省掉了一次開銷,QUIC 的基本資料傳輸單位是包(packet)和幀(frame),一個包由多個幀組成,包面向的是“連接”,幀面向的是“流”,
QUIC 使用不透明的“連接 ID”來標記通信的兩個端點,客戶端和服務器可以自行選擇一組 ID 來標記自己,這樣就解除了 TCP 里連接對“IP 地址 + 埠”(即常說的四元組)的強系結,支持“連接遷移”(Connection Migration),
HTTP/3
因為 QUIC 本身就已經支持了加密、流和多路復用,所以HTTP/3不需要定義流,而是直接使用 QUIC 的流,由于流管理被“下放”到了 QUIC,所以 HTTP/3 里幀的結構也變簡單了,幀頭只有兩個欄位:型別和長度,而且同樣都采用變長編碼,最小只需要兩個位元組,
作者:yutingbai
本文來自博客園,作者:古道輕風,轉載請注明原文鏈接:https://www.cnblogs.com/88223100/p/Understanding-HTTP-is-enough.html
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/547020.html
標籤:HTML5
上一篇:藍牙-低功耗中心設備