1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        半小時(shí)搞懂 HTTP、HTTPS和HTTP2

        共 13532字,需瀏覽 28分鐘

         ·

        2021-01-06 20:35

        另外,建議在學(xué)習(xí) HTTP 知識(shí)的時(shí)候,利用 Chrome 開發(fā)者工具來做實(shí)踐,這可以幫助你理解得更深刻。

        (此圖在網(wǎng)上找來的,侵刪)

        HTTP 概述

        HTTP 超文本傳輸協(xié)議是位于 TCP/IP 體系結(jié)構(gòu)中的應(yīng)用層協(xié)議,它是萬維網(wǎng)數(shù)據(jù)通信的基礎(chǔ)。

        當(dāng)我們?cè)L問一個(gè)網(wǎng)站時(shí),需要通過統(tǒng)一資源定位符(uniform resource locator,URL)來定位服務(wù)器并獲取資源。

        <協(xié)議>://<域名>:<端口>/<路徑>

        復(fù)制代碼

        一個(gè) URL 的一般形式通常如上所示(http://test.com/index.html ),現(xiàn)在最常用的協(xié)議就是 HTTP,HTTP 的默認(rèn)端口是 80,通常可以省略。

        HTTP/1.1

        HTTP/1.1 是目前使用最廣泛的版本,一般沒有特別標(biāo)明版本都是指 HTTP/1.1。

        HTTP 連接建立過程

        我們來看一下在瀏覽器輸入 URL 后獲取 HTML 頁面的過程。

        1. 先通過域名系統(tǒng)(Domain Name System,DNS)查詢將域名轉(zhuǎn)換為 IP 地址。即將 test.com 轉(zhuǎn)換為 221.239.100.30 這一過程。
        2. 通過三次握手(稍后會(huì)講)建立 TCP 連接。
        3. 發(fā)起 HTTP 請(qǐng)求。
        4. 目標(biāo)服務(wù)器接收到 HTTP 請(qǐng)求并處理。
        5. 目標(biāo)服務(wù)器往瀏覽器發(fā)回 HTTP 響應(yīng)。
        6. 瀏覽器解析并渲染頁面。

        下圖中的 RTT 為往返時(shí)延(Round-Trip Time:往返時(shí)延。表示從發(fā)送端發(fā)送數(shù)據(jù)開始,到發(fā)送端收到來自接收端的確認(rèn),總共經(jīng)歷的時(shí)延)。

        HTTP 連接拆除過程

        所有 HTTP 客戶端(瀏覽器)、服務(wù)器都可在任意時(shí)刻關(guān)閉 TCP 連接。通常會(huì)在一條報(bào)文結(jié)束時(shí)關(guān)閉連接,但出錯(cuò)的時(shí)候,也可能在首部行的中間或其他任意位置關(guān)閉連接。

        TCP 三次握手和四次揮手

        由于 HTTP 是基于 TCP 的,所以打算在這補(bǔ)充一下 TCP 連接建立和拆除的過程。

        首先,我們需要了解一些 TCP 報(bào)文段的字段和標(biāo)志位:

        1. 32 比特的序號(hào)字段和確認(rèn)號(hào)字段,TCP 字節(jié)流每一個(gè)字節(jié)都按順序編號(hào)。確認(rèn)號(hào)是接收方期望從對(duì)方收到的下一字節(jié)的序號(hào)。
        2. ACK 標(biāo)志位,用于指示確認(rèn)字段中的值是有效的 ACK=1 有效,ACK=0 無效。
        3. SYN 標(biāo)志位,用于連接建立,SYN 為 1 時(shí),表明這是一個(gè)請(qǐng)求建立連接報(bào)文。
        4. FIN 標(biāo)志位,用于連接拆除,F(xiàn)IN 為 1 時(shí),表明發(fā)送方數(shù)據(jù)已發(fā)送完畢,并要求釋放連接。

        TCP 三次握手建立連接

        TCP 標(biāo)準(zhǔn)規(guī)定,ACK 報(bào)文段可以攜帶數(shù)據(jù),但不攜帶數(shù)據(jù)就不用消耗序號(hào)。

        1. 客戶端發(fā)送一個(gè)不包含應(yīng)用層數(shù)據(jù)的 TCP 報(bào)文段,首部的 SYN 置為 1,隨機(jī)選擇一個(gè)初始序號(hào)(一般為 0)放在 TCP 報(bào)文段的序號(hào)字段中。(SYN 為 1 的時(shí)候,不能攜帶數(shù)據(jù),但要消耗掉一個(gè)序號(hào))
        2. TCP 報(bào)文段到達(dá)服務(wù)器主機(jī)后,服務(wù)器提取報(bào)文段,并為該 TCP 連接分配緩存和變量。然后向客戶端發(fā)送允許連接的 ACK 報(bào)文段(不包含應(yīng)用層數(shù)據(jù))。這個(gè)報(bào)文段的首部包含 4 個(gè)信息:ACK 置 為 1,SYN 置為 1;確認(rèn)號(hào)字段置為客戶端的序號(hào) + 1;隨機(jī)選擇自己的初始序號(hào)(一般為 0)。
        3. 收到服務(wù)器的 TCP 響應(yīng)報(bào)文段后,客戶端也要為該 TCP 連接分配緩存和變量,并向服務(wù)器發(fā)送一個(gè) ACK 報(bào)文段。這個(gè)報(bào)文段將服務(wù)器端的序號(hào) + 1 放置在確認(rèn)號(hào)字段中,用來對(duì)服務(wù)器允許連接的報(bào)文段進(jìn)行響應(yīng),因?yàn)檫B接已經(jīng)建立,所以 SYN 置為 0。最后一個(gè)階段,報(bào)文段可以攜帶客戶到服務(wù)器的數(shù)據(jù)。并且以后的每一個(gè)報(bào)文段,SYN 都置為 0。

        下圖是一個(gè)具體的示例:

        (此截圖是我使用 Wireshark 抓包工具截取的 TCP 報(bào)文段截圖)。

        TCP 四次揮手拆除連接

        FIN 報(bào)文段即使不攜帶數(shù)據(jù),也要消耗序號(hào)。

        1. 客戶端發(fā)送一個(gè) FIN 置為 1 的報(bào)文段。
        2. 服務(wù)器回送一個(gè)確認(rèn)報(bào)文段。
        3. 服務(wù)器發(fā)送 FIN 置為 1 的報(bào)文段。
        4. 客戶端回送一個(gè)確認(rèn)報(bào)文段。

        TCP 為什么是四次揮手,而不是三次?

        1. 當(dāng) A 給 B 發(fā)送 FIN 報(bào)文時(shí),代表 A 不再發(fā)送報(bào)文,但仍可以接收?qǐng)?bào)文。
        2. B 可能還有數(shù)據(jù)需要發(fā)送,因此先發(fā)送 ACK 報(bào)文,告知 A “我知道你想斷開連接的請(qǐng)求了”。這樣 A 便不會(huì)因?yàn)闆]有收到應(yīng)答而繼續(xù)發(fā)送斷開連接的請(qǐng)求(即 FIN 報(bào)文)。
        3. B 在處理完數(shù)據(jù)后,就向 A 發(fā)送一個(gè) FIN 報(bào)文,然后進(jìn)入 LAST_ACK 階段(超時(shí)等待)。
        4. A 向 B 發(fā)送 ACK 報(bào)文,雙方都斷開連接。

        參考資料:

        • 知乎網(wǎng)友 - 魔方的回答

        HTTP 報(bào)文格式

        HTTP 報(bào)文由請(qǐng)求行、首部、實(shí)體主體組成,它們之間由 CRLF(回車換行符) 分隔開。

        注意:實(shí)體包括首部 (也稱為實(shí)體首部) 和實(shí)體主體,sp 即是空格 space。

        請(qǐng)求行和首部是由 ASCII 文本組成的,實(shí)體主體是可選的,可以為空也可以是任意二進(jìn)制數(shù)據(jù)。

        請(qǐng)求報(bào)文和響應(yīng)報(bào)文的格式基本相同。

        請(qǐng)求報(bào)文格式

        ??



        復(fù)制代碼

        響應(yīng)報(bào)文格式

        ??



        復(fù)制代碼

        一個(gè)請(qǐng)求或響應(yīng)報(bào)文由以下字段組成

        1. 請(qǐng)求方法,客戶端希望服務(wù)器對(duì)資源執(zhí)行的動(dòng)作。
        2. 請(qǐng)求 URL,命名了所請(qǐng)求的資源。
        3. 協(xié)議版本,報(bào)文所使用的 HTTP 版本。
        4. 狀態(tài)碼,這三位數(shù)字描述了請(qǐng)求過程中所發(fā)生的情況。
        5. 原因短語,數(shù)字狀態(tài)碼的可讀版本(例如上面的響應(yīng)示例跟在 200 后面的 OK,一般按規(guī)范寫最好)。
        6. 首部,可以有零或多個(gè)首部。
        7. 實(shí)體的主體部分,可以為空也可以包含任意二進(jìn)制數(shù)據(jù)。

        一個(gè) HTTP 請(qǐng)求示例

        GET?/2.app.js?HTTP/1.1
        Host:?118.190.217.8:3389
        Connection:?keep-alive
        User-Agent:?Mozilla/5.0?(Windows?NT?10.0;?Win64;?x64)?AppleWebKit/537.36?(KHTML,?like?Gecko)?Chrome/80.0.3987.122?Safari/537.36
        Accept:?\*/\*
        Referer:?http://118.190.217.8:3389/
        Accept-Encoding:?gzip,?deflate
        Accept-Language:?zh-CN,zh;q=0.9

        復(fù)制代碼

        一個(gè) HTTP 響應(yīng)示例

        HTTP/1.1?200?OK
        X-Powered-By:?Express
        Accept-Ranges:?bytes
        Cache-Control:?public,?max-age=0
        Last-Modified:?Sat,?07?Mar?2020?03:52:30?GMT
        ETag:?W/"253e-170b31f7de7"
        Content-Type:?application/javascript;?charset=UTF-8
        Vary:?Accept-Encoding
        Content-Encoding:?gzip
        Date:?Fri,?15?May?2020?05:38:05?GMT
        Connection:?keep-alive
        Transfer-Encoding:?chunked

        復(fù)制代碼

        方法

        方法描述
        GET從服務(wù)器獲取一份文檔
        HEAD只從服務(wù)器獲取文檔的頭部
        POST向服務(wù)器發(fā)送需要處理的數(shù)據(jù)
        PUT將請(qǐng)求的數(shù)據(jù)部分存儲(chǔ)在服務(wù)器上
        TRACE對(duì)可能經(jīng)過代理服務(wù)器傳送到服務(wù)器上去的報(bào)文進(jìn)行追蹤
        OPTIONS決定可以在服務(wù)器上執(zhí)行哪些方法
        DELETE從服務(wù)器上刪除一份文檔
        GET 和 HEAD

        其中 GET 和 HEAD 被稱為安全方法,因?yàn)樗鼈兪莾绲鹊模ㄈ绻粋€(gè)請(qǐng)求不管執(zhí)行多少次,其結(jié)果都是一樣的,這個(gè)請(qǐng)求就是冪等的),類似于 POST 就不是冪等的。

        HEAD 方法和 GET 方法很類似,但服務(wù)器在響應(yīng)中只返回首部。這就允許客戶端在未獲取實(shí)際資源的情況下,對(duì)資源的首部進(jìn)行檢查。使用 HEAD,可以:

        1. 在不獲取資源的情況下了解資源的情況。
        2. 通過查看響應(yīng)狀態(tài)碼,看看某個(gè)對(duì)象是否存在。
        3. 通過查看首部,了解測(cè)試資源是否被修改了。

        服務(wù)器開發(fā)者必須確保返回的首部與 GET 請(qǐng)求所返回的首部完全相同。遵循 HTTP/1.1 規(guī)范,就必須實(shí)現(xiàn) HEAD 方法。

        PUT

        與 GET 方法從服務(wù)器讀取文檔相反,PUT 方法會(huì)向服務(wù)器寫入文檔。PUT 方法的語義就是讓服務(wù)器用請(qǐng)求的主體部分來創(chuàng)建一個(gè)由所請(qǐng)求的 URL 命名的新文檔。如果那個(gè)文檔已存在,就覆蓋它。

        POST

        POST 方法通常用來向服務(wù)器發(fā)送表單數(shù)據(jù)。

        TRACE

        客戶端發(fā)起一個(gè)請(qǐng)求時(shí),這個(gè)請(qǐng)求可能要穿過路由器、防火墻、代理、網(wǎng)關(guān)等。每個(gè)中間節(jié)點(diǎn)都可能會(huì)修改原始的 HTTP 請(qǐng)求,TRACE 方法允許客戶端在最終發(fā)起請(qǐng)求時(shí),看看它變成了什么樣子。

        TRACE 請(qǐng)求會(huì)在目的服務(wù)器端發(fā)起一個(gè) “環(huán)回” 診斷。行程最后一站的服務(wù)器會(huì)彈回一條 TRACE 響應(yīng),并在響應(yīng)主體中攜帶它收到的原始請(qǐng)求報(bào)文。這樣客戶端就可以查看在所有中間 HTTP 應(yīng)用程序組成的請(qǐng)求 / 響應(yīng)鏈上,原始報(bào)文是否被毀壞或修改過。

        TRACE 方法主要用于診斷,用于驗(yàn)證請(qǐng)求是否如愿穿過了請(qǐng)求 / 響應(yīng)鏈。它也是一種工具,用來查看代理和其他應(yīng)用程序?qū)τ脩粽?qǐng)求所產(chǎn)生的效果。TRACE 請(qǐng)求中不能帶有實(shí)體的主體部分。TRACE 響應(yīng)的實(shí)體主體部分包含了響應(yīng)服務(wù)器收到的請(qǐng)求的精確副本。

        OPTIONS

        OPTIONS 方法請(qǐng)求 Web 服務(wù)器告知其支持的各種功能。

        DELETE

        DELETE 方法就是讓服務(wù)器刪除請(qǐng)求 URL 所指定的資源。

        狀態(tài)碼

        整體范圍已定義范圍分類
        100~199100~101信息提示
        200~299200~206成功
        300~399300~305重定向
        400~499400~415客戶端錯(cuò)誤
        500~599500~505服務(wù)器錯(cuò)誤
        300~399 重定向狀態(tài)碼

        重定向狀態(tài)碼要么告訴客戶端使用替代位置來訪問他們感興趣的資源,要么提供一個(gè)替代的響應(yīng)而不是資源的內(nèi)容。如果資源已被移動(dòng),可以發(fā)送一個(gè)重定向狀態(tài)碼和一個(gè)可選的 Location 首部來告知客戶端資源已被移走,以及現(xiàn)在在哪里可以找到它。這樣,瀏覽器可以在不打擾使用者的情況下,透明地轉(zhuǎn)入新的位置。

        400~499 客戶端錯(cuò)誤狀態(tài)碼

        有時(shí)客戶端會(huì)發(fā)送一些服務(wù)器無法處理的東西,例如格式錯(cuò)誤的請(qǐng)求報(bào)文、一個(gè)不存在的 URL。

        500~599 服務(wù)器錯(cuò)誤狀態(tài)碼

        有時(shí)客戶端發(fā)送了一條有效請(qǐng)求,服務(wù)器自身卻出錯(cuò)了。

        首部

        首部和方法共同配合工作,決定了客戶端和服務(wù)器能做什么事情。

        首部分類

        1. 通用首部,可以出現(xiàn)在請(qǐng)求或響應(yīng)報(bào)文中。
        2. 請(qǐng)求首部,提供更多有關(guān)請(qǐng)求的信息。
        3. 響應(yīng)首部,提供更多有關(guān)響應(yīng)的信息。
        4. 實(shí)體首部,描述主體的長(zhǎng)度和內(nèi)容,或者資源自身。
        5. 擴(kuò)展首部,規(guī)范中沒有定義的新首部。
        通用首部

        有些首部提供了與報(bào)文相關(guān)的最基本信息,它們被稱為通用首部。以下是一些常見的通用首部:

        請(qǐng)求首部

        請(qǐng)求首部是只在請(qǐng)求報(bào)文中有意義的首部,用于說明請(qǐng)求的詳情。以下是一些常見的請(qǐng)求首部:

        響應(yīng)首部

        響應(yīng)首部讓服務(wù)器為客戶端提供了一些額外的信息。

        實(shí)體首部

        實(shí)體首部提供了有關(guān)實(shí)體及其內(nèi)容的大量信息,從有關(guān)對(duì)象類型的信息,到能夠?qū)Y源使用的各種有效的請(qǐng)求方法。

        例如內(nèi)容首部,提供了與實(shí)體內(nèi)容有關(guān)的特定信息,說明了其類型、尺寸以及處理它所需的其他有用信息。另外,通用的緩存首部說明了如何或什么時(shí)候進(jìn)行緩存。實(shí)體的緩存首部提供了與被緩存實(shí)體有關(guān)的信息。

        性能優(yōu)化

        1. 減少 HTTP 請(qǐng)求

        每發(fā)起一個(gè) HTTP 請(qǐng)求,都得經(jīng)歷三次握手建立 TCP 連接,如果連接只用來交換少量數(shù)據(jù),這個(gè)過程就會(huì)嚴(yán)重降低 HTTP 性能。所以我們可以將多個(gè)小文件合成一個(gè)大文件,從而減少 HTTP 請(qǐng)求次數(shù)。

        其實(shí)由于持久連接(重用 TCP 連接,以消除連接及關(guān)閉時(shí)延;HTTP/1.1 默認(rèn)開啟持久連接)的存在,每個(gè)新請(qǐng)求不一定都需要建立一個(gè)新的 TCP 連接。但是,瀏覽器處理完一個(gè) HTTP 請(qǐng)求才能發(fā)起下一個(gè),所以在 TCP 連接數(shù)沒達(dá)到瀏覽器規(guī)定的上限時(shí),還是會(huì)建立新的 TCP 連接。從這點(diǎn)來看,減少 HTTP 請(qǐng)求仍然是有必要的。

        2. 靜態(tài)資源使用 CDN

        內(nèi)容分發(fā)網(wǎng)絡(luò)(CDN)是一組分布在多個(gè)不同地理位置的 Web 服務(wù)器。我們都知道,當(dāng)服務(wù)器離用戶越遠(yuǎn)時(shí),延遲越高。CDN 就是為了解決這一問題,在多個(gè)位置部署服務(wù)器,讓用戶離服務(wù)器更近,從而縮短請(qǐng)求時(shí)間。

        3. 善用緩存

        為了避免用戶每次訪問網(wǎng)站都得請(qǐng)求文件,我們可以通過添加 Expires 頭來控制這一行為。Expires 設(shè)置了一個(gè)時(shí)間,只要在這個(gè)時(shí)間之前,瀏覽器都不會(huì)請(qǐng)求文件,而是直接使用緩存。

        不過這樣會(huì)產(chǎn)生一個(gè)問題,當(dāng)文件更新了怎么辦?怎么通知瀏覽器重新請(qǐng)求文件?

        可以通過更新頁面中引用的資源鏈接地址,讓瀏覽器主動(dòng)放棄緩存,加載新資源。

        具體做法是把資源地址 URL 的修改與文件內(nèi)容關(guān)聯(lián)起來,也就是說,只有文件內(nèi)容變化,才會(huì)導(dǎo)致相應(yīng) URL 的變更,從而實(shí)現(xiàn)文件級(jí)別的精確緩存控制。什么東西與文件內(nèi)容相關(guān)呢?我們會(huì)很自然的聯(lián)想到利用數(shù)據(jù)摘要要算法對(duì)文件求摘要信息,摘要信息與文件內(nèi)容一一對(duì)應(yīng),就有了一種可以精確到單個(gè)文件粒度的緩存控制依據(jù)了。

        參考資料:

        • 張?jiān)讫?-- 大公司里怎樣開發(fā)和部署前端代碼?

        4. 壓縮文件

        壓縮文件可以減少文件下載時(shí)間,讓用戶體驗(yàn)性更好。

        gzip 是目前最流行和最有效的壓縮方法??梢酝ㄟ^向 HTTP 請(qǐng)求頭中的 Accept-Encoding 頭添加 gzip 標(biāo)識(shí)來開啟這一功能。當(dāng)然,服務(wù)器也得支持這一功能。

        舉個(gè)例子,我用 Vue 開發(fā)的項(xiàng)目構(gòu)建后生成的 app.js 文件大小為 1.4MB,使用 gzip 壓縮后只有 573KB,體積減少了將近 60%。

        5. 通過 max-age 和 no-cache 實(shí)現(xiàn)文件精確緩存

        通用消息頭部 Cache-Control 其中有兩個(gè)選項(xiàng):

        1. max-age: 設(shè)置緩存存儲(chǔ)的最大周期,超過這個(gè)時(shí)間緩存被認(rèn)為過期 (單位秒)。在這個(gè)時(shí)間前,瀏覽器讀取文件不會(huì)發(fā)出新請(qǐng)求,而是直接使用緩存。
        2. no-cache: 指定 no-cache 表示客戶端可以緩存資源,每次使用緩存資源前都必須重新驗(yàn)證其有效性。

        我們可以將那些長(zhǎng)期不變的靜態(tài)資源設(shè)置一個(gè)非常長(zhǎng)的緩存時(shí)間,例如設(shè)置成緩存一年。

        然后將 index.html 文件設(shè)置成 no-cache。這樣每次訪問網(wǎng)站時(shí),瀏覽器都會(huì)詢問 index.html 是否有更新,如果沒有,就使用舊的 index.html 文件。如果有更新,就讀取新的 index.html 文件。當(dāng)加載新的 index.html 時(shí),也會(huì)去加載里面新的 URL 資源。

        例如 index.html 原來引用了 a.jsb.js,現(xiàn)在更新了變成 a.jsc.js。那就只會(huì)加載 c.js 文件。

        具體請(qǐng)看 webpack + express 實(shí)現(xiàn)文件精確緩存。

        HTTPS

        HTTPS 是最流行的 HTTP 安全形式,由網(wǎng)景公司首創(chuàng),所有主要的瀏覽器和服務(wù)器都支持此協(xié)議。使用 HTTPS 時(shí),所有的 HTTP 請(qǐng)求和響應(yīng)數(shù)據(jù)在發(fā)送之前,都要進(jìn)行加密。加密可以使用 SSL 或 TLS。

        SSL/TLS 協(xié)議作用在 HTTP 協(xié)議之下,對(duì)于上層應(yīng)用來說,原來的發(fā)送 / 接收數(shù)據(jù)流程不變,這就很好地兼容了老的 HTTP 協(xié)議。由于 SSL/TLS 差別不大,下面統(tǒng)一使用 SSL。

        要想了解 HTTPS 為何安全,還得繼續(xù)了解一下這些概念:加密算法、摘要算法、數(shù)字簽名數(shù)字證書

        加密算法

        對(duì)稱密鑰密碼體制

        對(duì)稱密鑰密碼體制,即加密密鑰和解密密鑰是使用相同的密碼體制。對(duì)稱密鑰加密技術(shù)的缺點(diǎn)之一就是發(fā)送者和接收者在對(duì)話之前,一定要有一個(gè)共享的密鑰,所以不太安全。

        公鑰密碼體制

        公鑰密碼體制使用不同的加密密鑰與解密密鑰。公鑰密碼體制產(chǎn)生的主要原因有兩個(gè):一是對(duì)稱密鑰密碼體制的密鑰分配問題,二是對(duì)數(shù)字簽名的需求。

        在公鑰密碼體制中,加密密鑰是公開的,解密密鑰是需要保密的,加密算法和解密算法也是公開的。

        公鑰密碼體制的加密和解密有如下特點(diǎn):

        1. 密鑰對(duì)產(chǎn)生器產(chǎn)生出接收者 B 的一對(duì)密鑰,即加密密鑰 PK 和解密密鑰 SK。
        2. 發(fā)送者 A 用 B 的公鑰 PK 作為加密密鑰來加密信息,B 接收后用解密密鑰 SK 解密。

        使用對(duì)稱密鑰時(shí),由于雙方使用同樣的密鑰,因此在通信信道上可以進(jìn)行一對(duì)一的雙向保密通信,雙方都可以用同一個(gè)密鑰加密解密。

        使用公開密鑰時(shí),在通信信道上可以是多對(duì)一的單向保密信道。即可以有多人持有 B 的公鑰,但只有 B 才能解密。

        摘要算法

        摘要算法的主要特征是加密過程不需要密鑰,并且經(jīng)過加密的數(shù)據(jù)無法被解密,目前可以被解密逆向的只有 CRC32 算法,只有輸入相同的明文數(shù)據(jù)經(jīng)過相同的消息摘要算法才能得到相同的密文。

        數(shù)字簽名

        用加密系統(tǒng)對(duì)報(bào)文進(jìn)行簽名,以說明是誰編寫的報(bào)文,同時(shí)證明報(bào)文未被篡改過,這種技術(shù)稱為數(shù)字簽名。

        數(shù)字簽名是附加在報(bào)文上的特殊加密校驗(yàn)碼。使用數(shù)字簽名的好處有:

        1. 簽名可以證明是作者編寫了這條報(bào)文。只有作者才會(huì)有最機(jī)密的私有密鑰,因此,只有作者才能計(jì)算出這些校驗(yàn)和。
        2. 簽名可以防止報(bào)文被篡改,如果有人在報(bào)文傳輸過程中對(duì)其進(jìn)行了修改,校驗(yàn)和就不再匹配了。

        數(shù)字簽名通常是用非對(duì)稱公開密鑰技術(shù)產(chǎn)生的。

        看上圖,任何人都能用 A 的公鑰 PK 對(duì)密文進(jìn)行 E 運(yùn)算后得到 A 發(fā)送的明文??梢娺@種通信并非為了保密,而是為了進(jìn)行簽名和核實(shí)簽名,即確認(rèn)此信息是 A 發(fā)送的(使用 A 的密鑰進(jìn)行加密的報(bào)文,只有使用 A 的公鑰才能正確解密)。但上述過程僅對(duì)報(bào)文進(jìn)行了簽名,對(duì)報(bào)文 X 本身卻未保密,所以要采用下圖的方法,同時(shí)實(shí)現(xiàn)秘密通信和數(shù)字簽名。

        數(shù)字證書

        假如你想訪問一個(gè)網(wǎng)站,怎么確保對(duì)方給你的公鑰是你想訪問的網(wǎng)站的公鑰,而不是被中間人篡改過的?

        數(shù)字證書的出現(xiàn)就是為了解決這個(gè)問題,它是由數(shù)字證書認(rèn)證機(jī)構(gòu)頒發(fā)的,用來證明公鑰擁有者的身份。換句話說,數(shù)字證書的作用就相當(dāng)于人的身份證,身份證證明了張三就是張三,而不是別人。

        數(shù)字證書一般包含以下內(nèi)容

        1. 對(duì)象的名稱(人、服務(wù)器、組織等);
        2. 過期時(shí)間;
        3. 證書發(fā)布者(由誰為證書擔(dān)保);
        4. 來自證書發(fā)布者的數(shù)字簽名;
        5. 對(duì)象的公鑰;
        6. 對(duì)象和所用簽名算法的描述性信息。

        任何人都可以創(chuàng)建一個(gè)數(shù)字證書,但由誰來擔(dān)保才是重點(diǎn)。

        數(shù)字證書的數(shù)字簽名計(jì)算過程

        1. 用摘要算法對(duì)數(shù)字證書的內(nèi)容計(jì)算出摘要;
        2. 用數(shù)字證書的私鑰對(duì)摘要進(jìn)行加密得到數(shù)字簽名。

        當(dāng)瀏覽器收到證書時(shí),會(huì)對(duì)簽名頒發(fā)機(jī)構(gòu)進(jìn)行驗(yàn)證,如果頒發(fā)機(jī)構(gòu)是個(gè)很有權(quán)威的公共簽名機(jī)構(gòu),瀏覽器可能就知道其公開密鑰了(瀏覽器會(huì)預(yù)裝很多簽名頒發(fā)機(jī)構(gòu)的證書)。如果對(duì)簽名頒發(fā)機(jī)構(gòu)一無所知,瀏覽器通常會(huì)向用戶顯示一個(gè)對(duì)話框,看看他是否相信這個(gè)簽名發(fā)布者。

        因?yàn)閿?shù)字證書的公鑰是公開的,任何人都可以用公鑰解密出數(shù)字證書的數(shù)字簽名的摘要,然后再用同樣的摘要算法對(duì)證書內(nèi)容進(jìn)行摘要計(jì)算,將得出的摘要和解密后的摘要作對(duì)比,如果內(nèi)容一致則說明這個(gè)證書沒有被篡改過,可以信任。

        這個(gè)過程是建立在被大家所認(rèn)可的證書機(jī)構(gòu)之上得到的公鑰,所以這是一種安全的方式。

        HTTPS 連接建立過程

        HTTPS 連接建立過程和 HTTP 差不多,區(qū)別在于 HTTP(默認(rèn)端口 80) 請(qǐng)求只要在 TCP 連接建立后就可以發(fā)起,而 HTTPS(默認(rèn)端口 443) 在 TCP 連接建立后,還需要經(jīng)歷 SSL 協(xié)議握手,成功后才能發(fā)起請(qǐng)求。

        我知道肯定會(huì)有人不滿足于簡(jiǎn)化版的 SSL 握手過程,所以我找了一篇文章 SSL/TLS 握手過程詳解,這篇文章非常詳細(xì)的講解了 SSL 握手的每一步驟。建議有興趣的同學(xué)看一看。

        HTTP/2

        HTTP/2 是 HTTP/1.x 的擴(kuò)展,而非替代。所以 HTTP 的語義不變,提供的功能不變,HTTP 方法、狀態(tài)碼、URL 和首部字段等這些核心概念也不變。

        之所以要遞增一個(gè)大版本到 2.0,主要是因?yàn)樗淖兞丝蛻舳伺c服務(wù)器之間交換數(shù)據(jù)的方式。HTTP 2.0 增加了新的二進(jìn)制分幀數(shù)據(jù)層,而這一層并不兼容之前的 HTTP 1.x 服務(wù)器及客戶端——是謂 2.0。

        HTTP/2 連接建立過程

        現(xiàn)在的主流瀏覽器 HTTP/2 的實(shí)現(xiàn)都是基于 SSL/TLS 的,也就是說使用 HTTP/2 的網(wǎng)站都是 HTTPS 協(xié)議的,所以本文只討論基于 SSL/TLS 的 HTTP/2 連接建立過程。

        基于 SSL/TLS 的 HTTP/2 連接建立過程和 HTTPS 差不多。在 SSL/TLS 握手協(xié)商過程中,客戶端在 ClientHello 消息中設(shè)置 ALPN(應(yīng)用層協(xié)議協(xié)商)擴(kuò)展來表明期望使用 HTTP/2 協(xié)議,服務(wù)器用同樣的方式回復(fù)。通過這種方式,HTTP/2 在 SSL/TLS 握手協(xié)商過程中就建立起來了。

        HTTP/1.1 的問題

        1. 隊(duì)頭阻塞

        在 HTTP 請(qǐng)求應(yīng)答過程中,如果出現(xiàn)了某種情況,導(dǎo)致響應(yīng)一直未能完成,那后面所有的請(qǐng)求就會(huì)一直阻塞著,這種情況叫隊(duì)頭阻塞。

        2. 低效的 TCP 利用

        由于 TCP 慢啟動(dòng)機(jī)制,導(dǎo)致每個(gè) TCP 連接在一開始的時(shí)候傳輸速率都不高,在處理多個(gè)請(qǐng)求后,才會(huì)慢慢達(dá)到 “合適” 的速率。對(duì)于請(qǐng)求數(shù)據(jù)量很小的 HTTP 請(qǐng)求來說,這種情況就是種災(zāi)難。

        3. 臃腫的消息首部

        HTTP/1.1 的首部無法壓縮,再加上 cookie 的存在,經(jīng)常會(huì)出現(xiàn)首部大小比請(qǐng)求數(shù)據(jù)大小還大的情況。

        4. 受限的優(yōu)先級(jí)設(shè)置

        HTTP/1.1 無法為重要的資源指定優(yōu)先級(jí),每個(gè) HTTP 請(qǐng)求都是一視同仁。

        在繼續(xù)討論 HTTP/2 的新功能之前,先把 HTTP/1.1 的問題列出來是有意義的。因?yàn)?HTTP/2 的某些新功能就是為了解決上述某些問題而產(chǎn)生的。

        二進(jìn)制分幀層

        HTTP/2 是基于幀的協(xié)議。采用分幀是為了將重要信息封裝起來,讓協(xié)議的解析方可以輕松閱讀、解析并還原信息。

        而 HTTP/1.1 是以文本分隔的。解析 HTTP/1.1 不需要什么高科技,但往往速度慢且容易出錯(cuò)。你需要不斷地讀入字節(jié),直到遇到分隔符 CRLF 為止,同時(shí)還要考慮不守規(guī)矩的客戶端,它只會(huì)發(fā)送 LF。

        解析 HTTP/1.1 的請(qǐng)求或響應(yīng)還會(huì)遇到以下問題:

        1. 一次只能處理一個(gè)請(qǐng)求或響應(yīng),完成之前不能停止解析。
        2. 無法預(yù)判解析需要多少內(nèi)存。

        HTTP/2 有了幀,處理協(xié)議的程序就能預(yù)先知道會(huì)收到什么,并且 HTTP/2 有表示幀長(zhǎng)度的字段。

        幀結(jié)構(gòu)

        ?+-----------------------------------------------+
        ?|?????????????????Length?(24)???????????????????|
        ?+---------------+---------------+---------------+
        ?|???Type?(8)????|???Flags?(8)???|
        ?+-+-------------+---------------+-------------------------------+
        ?|R|?????????????????Stream?Identifier?(31)??????????????????????|
        ?+=+=============================================================+
        ?|???????????????????Frame?Payload?(0...)??????????????????????...
        ?+---------------------------------------------------------------+

        復(fù)制代碼

        名稱長(zhǎng)度描述
        Length3 字節(jié)表示幀負(fù)載的長(zhǎng)度,取值范圍為 (2 的 14 次方)至 (2 的 24 次方 - 1)。(2 的 14 次方) 16384 字節(jié)是默認(rèn)的最大幀大小,如果需要更大的幀,必須在 SETTINGS 幀中設(shè)置
        Type1 字節(jié)當(dāng)前幀類型(見下表)
        Flags1 字節(jié)具體幀類型的標(biāo)識(shí)
        R1 位保留位,不要設(shè)置,否則可能會(huì)帶來嚴(yán)重的后果
        Stream Identifier31 位每個(gè)流的唯一 ID
        Frame Payload長(zhǎng)度可變真實(shí)的幀內(nèi)容,長(zhǎng)度是在 Length 字段中設(shè)置的

        由于 HTTP/2 是分幀的,請(qǐng)求和響應(yīng)都可以多路復(fù)用,有助于解決類似類似隊(duì)頭阻塞的問題。

        幀類型

        名稱ID描述
        DATA0x0傳輸流的核心內(nèi)容
        HEADERS0x1包含 HTTP 首部,和可選的優(yōu)先級(jí)參數(shù)
        PRIORITY0x2指示或更改流的優(yōu)先級(jí)和依賴
        RST_STREAM0x3允許一端停止流(通常由于錯(cuò)誤導(dǎo)致的)
        SETTINGS0x4協(xié)商連接級(jí)參數(shù)
        PUSH_PROMISE0x5提示客戶端,服務(wù)器要推送些東西
        PING0x6測(cè)試連接可用性和往返時(shí)延(RTT)
        GOAWAY0x7告訴另一端,當(dāng)前的端已結(jié)束
        WINDOW_UPDATE0x8協(xié)商一端將要接收多少字節(jié)(用于流量控制)
        CONTINUATION0x9用以擴(kuò)展 HEADERS 模塊

        多路復(fù)用

        在 HTTP/1.1 中,如果客戶端想發(fā)送多個(gè)并行的請(qǐng)求,那么必須使用多個(gè) TCP 連接。

        而 HTTP/2 的二進(jìn)制分幀層突破了這一限制,所有的請(qǐng)求和響應(yīng)都在同一個(gè) TCP 連接上發(fā)送:客戶端和服務(wù)器把 HTTP 消息分解成多個(gè)幀,然后亂序發(fā)送,最后在另一端再根據(jù)流 ID 重新組合起來。

        這個(gè)機(jī)制為 HTTP 帶來了巨大的性能提升,因?yàn)椋?/p>

        • 可以并行交錯(cuò)地發(fā)送請(qǐng)求,請(qǐng)求之間互不影響;
        • 可以并行交錯(cuò)地發(fā)送響應(yīng),響應(yīng)之間互不干擾;
        • 只使用一個(gè)連接即可并行發(fā)送多個(gè)請(qǐng)求和響應(yīng);
        • 消除不必要的延遲,從而減少頁面加載的時(shí)間;
        • 不必再為繞過 HTTP 1.x 限制而多做很多工作;

        HTTP/2 規(guī)范對(duì)流的定義是:HTTP/2 連接上獨(dú)立的、雙向的幀序列交換。如果客戶端想要發(fā)出請(qǐng)求,它會(huì)開啟一個(gè)新流,然后服務(wù)器在這個(gè)流上回復(fù)。由于有分幀,所以多個(gè)請(qǐng)求和響應(yīng)可以交錯(cuò),而不會(huì)互相阻塞。流 ID 用來標(biāo)識(shí)幀所屬的流。

        客戶端到服務(wù)器的 HTTP/2 連接建立后,通過發(fā)送 HEADERS 幀來啟動(dòng)新的流。如果首部需要跨多個(gè)幀,可能還會(huì)發(fā)送 CONTINUATION 幀。該 HEADERS 幀可能來自請(qǐng)求或響應(yīng)。后續(xù)流啟動(dòng)的時(shí)候,會(huì)發(fā)送一個(gè)帶有遞增流 ID 的新 HEADERS 幀。

        消息

        HTTP 消息泛指 HTTP 請(qǐng)求或響應(yīng),消息由一或多個(gè)幀組成,這些幀可以亂序發(fā)送,然后再根據(jù)每個(gè)幀首部的流 ID 重新組裝。

        一個(gè)消息至少由 HEADERS 幀(它初始化流)組成,并且可以另外包含 CONTINUATION 和 DATA 幀,以及其他的 HEADERS 幀。

        HTTP/1.1 的請(qǐng)求和響應(yīng)部分都分成消息首部和消息體兩部分;HTTP/2 的請(qǐng)求和響應(yīng)分成 HEADERS 幀和 DATA 幀。

        優(yōu)先級(jí)

        把 HTTP 消息分解為很多獨(dú)立的幀之后,就可以通過優(yōu)化這些幀的交錯(cuò)和傳輸順序,進(jìn)一步提升性能。

        通過 HEADERS 幀和 PRIORITY 幀,客戶端可以明確地和服務(wù)器溝通它需要什么,以及它需要這些資源的順序。具體來講,服務(wù)器可以根據(jù)流的優(yōu)先級(jí),控制資源分配(CPU、內(nèi)存、帶寬),而在響應(yīng)數(shù)據(jù)準(zhǔn)備好之后,優(yōu)先將最高優(yōu)先級(jí)的幀發(fā)送給客戶端。

        流量控制

        在同一個(gè) TCP 連接上傳輸多個(gè)數(shù)據(jù)流,就意味著要共享帶寬。標(biāo)定數(shù)據(jù)流的優(yōu)先級(jí)有助于按序交付,但只有優(yōu)先級(jí)還不足以確定多個(gè)數(shù)據(jù)流或多個(gè)連接間的資源分配。

        為解決這個(gè)問題,HTTP/2 為數(shù)據(jù)流和連接的流量控制提供了一個(gè)簡(jiǎn)單的機(jī)制:

        • 流量控制基于每一跳進(jìn)行,而非端到端的控制;
        • 流量控制基于 WINDOW_UPDATE 幀進(jìn)行,即接收方廣播自己準(zhǔn)備接收某個(gè)數(shù)據(jù)流的多少字節(jié),以及對(duì)整個(gè)連接要接收多少字節(jié);
        • 流量控制窗口大小通過 WINDOW_UPDATE 幀更新,這個(gè)字段指定了流 ID 和窗口大小遞增值;
        • 流量控制有方向性,即接收方可能根據(jù)自己的情況為每個(gè)流乃至整個(gè)連接設(shè)置任意窗口大?。?/section>
        • 流量控制可以由接收方禁用,包括針對(duì)個(gè)別的流和針對(duì)整個(gè)連接。

        HTTP/2 連接建立之后,客戶端與服務(wù)器交換 SETTINGS 幀,目的是設(shè)置雙向的流量控制窗口大小。除此之外,任何一端都可以選擇禁用個(gè)別流或整個(gè)連接的流量控制。

        服務(wù)器推送

        HTTP/2 新增的一個(gè)強(qiáng)大的新功能,就是服務(wù)器可以對(duì)一個(gè)客戶端請(qǐng)求發(fā)送多個(gè)響應(yīng)。換句話說,除了對(duì)最初請(qǐng)求的響應(yīng)外,服務(wù)器還可以額外向客戶端推送資源,而無需客戶端明確地請(qǐng)求。

        為什么需要這樣一個(gè)機(jī)制呢?通常的 Web 應(yīng)用都由幾十個(gè)資源組成,客戶端需要分析服務(wù)器提供的文檔才能逐個(gè)找到它們。那為什么不讓服務(wù)器提前就把這些資源推送給客戶端,從而減少額外的時(shí)間延遲呢?服務(wù)器已經(jīng)知道客戶端下一步要請(qǐng)求什么資源了,這時(shí)候服務(wù)器推送即可派上用場(chǎng)。

        另外,客戶端也可以拒絕服務(wù)器的推送。

        首部壓縮

        HTTP/1.1 存在的一個(gè)問題就是臃腫的首部,HTTP/2 對(duì)這一問題進(jìn)行了改進(jìn),可以對(duì)首部進(jìn)行壓縮。在一個(gè) Web 頁面中,一般都會(huì)包含大量的請(qǐng)求,而其中有很多請(qǐng)求的首部往往有很多重復(fù)的部分。

        例如有如下兩個(gè)請(qǐng)求:

        :authority:?unpkg.zhimg.com
        :method:?GET
        :path:?/[email protected]/dist/zap.js
        :scheme:?https
        accept:?\*/\*
        accept-encoding:?gzip,?deflate,?br
        accept-language:?zh-CN,zh;q=0.9
        cache-control:?no-cache
        pragma:?no-cache
        referer:?https://www.zhihu.com/
        sec-fetch-dest:?script
        sec-fetch-mode:?no-cors
        sec-fetch-site:?cross-site
        user-agent:?Mozilla/5.0?(Windows?NT?6.1;?Win64;?x64)?AppleWebKit/537.36?(KHTML,?like?Gecko)?Chrome/80.0.3987.122?Safari/537.36

        復(fù)制代碼

        :authority:?zz.bdstatic.com
        :method:?GET
        :path:?/linksubmit/push.js
        :scheme:?https
        accept:?\*/\*
        accept-encoding:?gzip,?deflate,?br
        accept-language:?zh-CN,zh;q=0.9
        cache-control:?no-cache
        pragma:?no-cache
        referer:?https://www.zhihu.com/
        sec-fetch-dest:?script
        sec-fetch-mode:?no-cors
        sec-fetch-site:?cross-site
        user-agent:?Mozilla/5.0?(Windows?NT?6.1;?Win64;?x64)?AppleWebKit/537.36?(KHTML,?like?Gecko)?Chrome/80.0.3987.122?Safari/537.36

        復(fù)制代碼

        從上面兩個(gè)請(qǐng)求可以看出來,有很多數(shù)據(jù)都是重復(fù)的。如果可以把相同的首部存儲(chǔ)起來,僅發(fā)送它們之間不同的部分,就可以節(jié)省不少的流量,加快請(qǐng)求的時(shí)間。

        HTTP/2 在客戶端和服務(wù)器端使用 “首部表” 來跟蹤和存儲(chǔ)之前發(fā)送的鍵-值對(duì),對(duì)于相同的數(shù)據(jù),不再通過每次請(qǐng)求和響應(yīng)發(fā)送。

        下面再來看一個(gè)簡(jiǎn)化的例子,假設(shè)客戶端按順序發(fā)送如下請(qǐng)求首部:

        Header1:foo
        Header2:bar
        Header3:bat

        復(fù)制代碼

        當(dāng)客戶端發(fā)送請(qǐng)求時(shí),它會(huì)根據(jù)首部值創(chuàng)建一張表:

        索引首部名稱
        62Header1foo
        63Header2bar
        64Header3bat

        如果服務(wù)器收到了請(qǐng)求,它會(huì)照樣創(chuàng)建一張表。當(dāng)客戶端發(fā)送下一個(gè)請(qǐng)求的時(shí)候,如果首部相同,它可以直接發(fā)送這樣的首部塊:

        62?63?64

        復(fù)制代碼

        服務(wù)器會(huì)查找先前建立的表格,并把這些數(shù)字還原成索引對(duì)應(yīng)的完整首部。

        性能優(yōu)化

        使用 HTTP/2 代替 HTTP/1.1,本身就是一種巨大的性能提升。這小節(jié)要聊的是在 HTTP/1.1 中的某些優(yōu)化手段,在 HTTP/2 中是不必要的,可以取消的。

        取消合并資源

        在 HTTP/1.1 中要把多個(gè)小資源合并成一個(gè)大資源,從而減少請(qǐng)求。而在 HTTP/2 就不需要了,因?yàn)?HTTP/2 所有的請(qǐng)求都可以在一個(gè) TCP 連接發(fā)送。

        取消域名拆分

        取消域名拆分的理由同上,再多的 HTTP 請(qǐng)求都可以在一個(gè) TCP 連接上發(fā)送,所以不需要采取多個(gè)域名來突破瀏覽器 TCP 連接數(shù)限制這一規(guī)則了。

        參考資料

        • HTTP 權(quán)威指南
        • HTTP/2 基礎(chǔ)教程
        • SSL/TLS 握手過程詳解
        • 互聯(lián)網(wǎng)安全之?dāng)?shù)字簽名、數(shù)字證書與 PKI 系統(tǒng)
        • 計(jì)算機(jī)網(wǎng)絡(luò)(第 7 版)
        • Web 性能權(quán)威指南
        瀏覽 30
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評(píng)論
        圖片
        表情
        推薦
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            深夜久久AAAAA级毛片免费看 | 北条麻妃久久精品 | 亚洲婷婷丁香 | 久久精品亚洲一区二区三区画质 | 久久www免费人成看片好看吗 | 国产最猛黑人xxxxx猛交 | 男女瑟瑟视频 | xxxx恋老同性tv | 日韩三级片免费观看 | 91精品国产福利在线观看 |