前端日拱一卒D4——網路基礎與HTTP

DerekZ95發表於2019-03-04

前言

餘為前端菜鳥,感姿勢水平匱乏,難觀前端之大局。遂決定循前端知識之脈絡,以興趣為引,輔以幾分堅持,望於己能解惑致知、於同道能助力一二,豈不美哉。

本系列程式碼及文件均在 此處

網路層級

20170516149490559398728.png

  • 實體層(物理層):連線計算機(光纖、電纜線、無線電波、雙絞線等)。

  • 連結層(資料鏈路層):確定0 1的分組形式。

    • 乙太網協議

      一組電訊號組成一幀,一幀分為head和data兩部分,head中包含接收方MAC地址資訊,以廣播的方式向本網路內所有計算機傳送資料包,由接收方自己比對MAC地址判斷是否接收。

  • 網路層:主機到主機的通訊。

    • 網際網路由許多子網路組成,在同一子網中可以通過MAC地址以廣播形式找到目標,但是不同子網廣播不過去,所以需要在網路層引入新的地址用於查詢子網路,即網址。

    • IP協議

      IPV4規定網路地址由32個二進位制位組成,以IP地址與子網掩碼相加是否相等判斷是否位於同一個子網路。IP資料包放入到乙太網資料包的data部分,IP資料包同樣包含head和data兩部分。

    • ARP協議

      通過IP地址獲取MAC地址(不在同一子網交由閘道器處理),在同一個子網路中廣播發出資料包包含目標IP地址,MAC地址為FF:FF:FF:FF:FF:FF目標主機接收到後比對成功後報告自己的MAC地址,於是獲取到了MAC地址,可以把資料包傳送到子網路裡任一主機。

  • 傳輸層:埠到埠的通訊。(埠為每個使用網路卡的程式的編號)

    • UDP協議

      資料包放入到IP資料包的data中,同樣由head和data組成,head主要定義發出埠和接收埠,data為具體內容。

    • TCP協議

      有確認機制的UDP,每個資料包需要確認,過程複雜,消耗更多的資源。

  • 應用層:規定應用程式的資料格式。(DHCP,DNS,HTTP,FTP,SSH等)

20170516149490921439572.png

使用者角度

  • 網路通訊是主機間資料包交換,要交換資料需要知道雙方的MAC地址和IP地址。

  • 使用者可以通過靜態IP和動態IP兩種方式實現網路通訊配置。

    • 設定本機靜態IP、子網掩碼從而確定本機所處子網路,設定閘道器用於跨子網通訊,設定DNS伺服器地址用於DNS解析。
    • 利用DHCP協議,以廣播形式向DHCP伺服器獲取動態的IP地址。
  • 例項:訪問頁面。

    • 瀏覽器中輸入URL,從本地(瀏覽器->OS)DNS快取中獲取目標伺服器IP地址,本地沒有則向DNS伺服器請求,獲取到IP地址後快取到本地。
    • 判斷是否為同一子網路,是則資料包應包含本機和目標主機的MAC、IP地址,否則目標主機的MAC地址應改為閘道器MAC地址。
    • 組裝資料包,如上圖。
    • 建立TCP連線,經歷三次握手後在第三次將資料包傳送到目標伺服器,伺服器取出完整的TCP資料包後做處理,定位資源,將資源複本寫到TCP套接字做出HTTP響應,然後藉由TCP協議再傳送回來到客戶端。
    • 客戶端收到響應,進行頁面處理、展示。

HTTP

基礎

應用層協議,無狀態。

  • 請求/響應模型

    客戶端向服務端傳送請求,服務端根據接收到的請求,處理後向客戶端返回響應資訊。

    前端日拱一卒D4——網路基礎與HTTP

  • url

    協議型別:[//[訪問資源需要的憑證資訊@]伺服器地址[:埠號]][/資源層級UNIX檔案路徑]檔名[?查詢][#片段ID]

    用於定位資源,輸入url->客戶端展示的過程不再贅述

  • 請求/響應結構

    • 請求:請求行、請求頭、請求正文(只有POST有)
    • 響應:狀態行、響應頭、響應正文
    • 頭域:重點關注快取相關,這裡不贅述

    get和post區別在於前者引數在url後,後者在請求正文;前者有大小限制,後者無,後者有請求體,前者無

    關於狀態碼,一般來說簡單記憶如下:1XX 可續發 2XX 成功 3XX 重定向 4XX 客戶端錯誤 5XX 服務端錯誤

HTTP1.1

  • 長連線

    // 請求頭、響應頭中包含
    Connection: keep-alive
    複製程式碼

    1.1預設開啟長連線,使得連線在一段時間內維持開啟,後續請求可複用,減少建立連線的成本

  • 協議升級

    // 請求頭中包含
    Connection: Upgrade
    Upgrade: websocket
    複製程式碼

    升級為websocket協議,後續會談到

  • 快取控制

    cache-rule

    • 1.0的expires -> 1.1的cache-control

      後者是相對時間,兩者都存在時,以後者為判斷過期依據(瀏覽器判斷)

    • Etag與Last-Modified

      如果上次返回頭中有Etag,則帶上if-none-match資訊請求到服務端,服務端進行判斷Etag是否修改,選擇304/200

      如果上次返回頭中有Last-Modified,則帶上if-modified-since資訊請求道服務端,服務端判斷是否失效,返回304/200

  • 痛點

    • 明文傳輸,不安全
    • header過大,且很多時候header變化不大,資源浪費
    • keep-alive給服務端帶來效能問題
  • 需優化點

    • 頻寬
      • pay more
    • 延遲
      • DNS解析:解決:預解析與快取。
      • 建立連線消耗:基於TCP,每次建立連線都需要經歷三次握手,最快也要在第三次才能將報文傳送到服務端。解決:keep-alive/HTTP2
      • 瀏覽器阻塞:由於瀏覽器單域名下最大連線限制(6個),達到限制後會導致後續請求阻塞,解決:將域名分割槽,提高並行資源下載能力;合併資源,減少請求個數。

HTTPS

圖解

前端日拱一卒D4——網路基礎與HTTP

HTTPS執行在SSL/TLS上,SSL/TLS執行在TCP上,所有傳輸內容都是需要加密的,可以有效防劫持

前端日拱一卒D4——網路基礎與HTTP

握手階段:

  • 客戶端給出協議版本、客戶端生成的隨機數、支援的加密方法
  • 服務端收到後確認加密方法,返回數字證書,以及一個服務端生成的隨機數
  • 客戶端確認證書有效,生成一個隨機數,用證書彙總的公鑰加密隨機數,傳送給服務端
  • 服務端使用私鑰獲得客戶端傳送的隨機數
  • 根據約定的加密演算法,使用前面的三個隨機數生成會話金鑰,用來加密後續整個會話過程

加密解密

  • 公鑰和私鑰只用於加密/解密 對話金鑰(非對稱)
  • 安全與否取決於三個隨機數中的第三個能否被破解

對稱加密/非對稱加密

  • 使用一對金鑰,公鑰用來加密,私鑰不公開,用於解密,慢,但是更安全 ----> 非對稱加密
  • 金鑰在網路中傳輸,快但是不安全 ----> 對稱加密
  • 解決:用非對稱加密的公鑰加密對稱加密的金鑰,接收方用私鑰解密得到對稱金鑰,用於加密資訊(減少複雜度,降低伺服器壓力)

升級至HTTPS

  • github免費的github pages用來搭建個人部落格非常方便,感興趣的可以參考這裡

    在專案設定下選擇開啟HTTPS即可

    前端日拱一卒D4——網路基礎與HTTP

    小綠鎖很醒目

    前端日拱一卒D4——網路基礎與HTTP

  • 個人站點升級HTTPS

    • 從域名服務商獲取免費的SSL證書

      前端日拱一卒D4——網路基礎與HTTP

      按照流程填寫

      前端日拱一卒D4——網路基礎與HTTP

    • 下載證書到伺服器(我的是一年免費的谷歌gce)

    • 修改nginx配置

      server {
          listen 80;
          server_name pandora.derekz.cn;
          # 重定向到https
          rewrite ^(.*)$  https://$host$1 permanent;
      
          location / {
              root html;
              index index.html index.htm;
          }
      }
      server {
          # 順便換http2吧
          listen 443 ssl http2;
          server_name pandora.derekz.cn;
          root html;
          index index.html index.htm;
      
          # 你的證書路徑
          ssl_certificate   /etc/nginx/cert/xxxxxxx.pem;
          ssl_certificate_key  /etc/nginx/cert/xxxxxxx.key;
      
          ssl_session_timeout 5m;
          ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
          ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
          ssl_prefer_server_ciphers on;
      }
      複製程式碼
    • 重啟nginx,稍稍等待訪問個人網站

      前端日拱一卒D4——網路基礎與HTTP

HTTP2

SPDY

SPDY與HTTP2區別在於前者強制使用SSL傳輸協議,以及兩者在首部演算法上有所區別,SPDY出現於HTTP2前,特點與HTTP2類似:多路複用、伺服器推送、頭部壓縮等。這裡暫不討論。

核心——二進位制分幀

  • HTTP2採用完全二進位制的格式傳輸資料。二進位制資料在網路中傳輸單位一般為幀
  • 一個幀包含有:型別Type、長度Length、標記Flag、流標識Stream和Frame payload(幀有效載荷)
  • 多個幀形成幀的傳輸網路流,可以認為HTTP2是流式傳輸。

前端日拱一卒D4——網路基礎與HTTP

  • 不改變HTTP的語義,方法、首部、動詞都不受影響
  • 在應用層(HTTP2.0)和傳輸層(TCP)之間多了一個二進位制分幀層
  • 將請求的內容分割為幀,頭部資訊放入headers幀,body放入data幀
  • HTTP2.0所有的通訊都在一個連線上完成,每個資料流以訊息形式傳送,一個訊息包含一個或多個幀,可以亂序,到達目的地後根據幀首部的流識別符號重組

首部壓縮

  • 客戶端和伺服器端使用“首部表”來跟蹤和儲存之前傳送的鍵-值對
  • 如果首部不發生變化,那麼首部0開銷,此時首部自動使用之前請求的首部
  • 如果發生變化,只需要將變化的部分填入首部,同時更新兩端維護的首部表即可
  • 於是,並不會有分幀後多加了很多首部幀帶來的效能問題,反而提升了效能
  • 合併資源減少請求並不適用與HTTP2,因為都在一個連線上

雙向並行

前端日拱一卒D4——網路基礎與HTTP

不需要域名分割槽,因為不限制,而且可以雙向並行多個請求/響應

HTTP2的多路複用與1.x的keep-alive本質上有區別,一個位於傳輸層,一個位於應用層,且後者是序列的,前者允許多個檔案傳輸幀在圖個TCP連線中同時流式傳輸

服務端推送

location / {
  root   /usr/share/nginx/html;
  index  index.html index.htm;
  http2_push /style.css;
  http2_push /example.png;
}
複製程式碼

http2_push欄位,只請求了/index.html 卻返回了style.css等額外資料。待研究

遷移HTTP2

細心的小夥伴也許發現了上面的nginx conf檔案內有這麼一行

listen 443 ssl http2;
複製程式碼

從HTTPS遷移到HTTP2非常簡單,只需要修改nginx配置即可,最後開啟chrome可以看到http2的連線情況

前端日拱一卒D4——網路基礎與HTTP

思考

我們說一個網頁的效能多好,最直接的一個表現是從enter敲下到頁面展示花的時間多短,也就是我們追求的低延遲高頻寬。頻寬隨著網路基礎建設不斷提高,所以效能瓶頸主要在於低延遲的難實現。

想想看,我們又要DNS解析,又要建立連線,還要加密解密,歷經千難萬險才能把請求資訊送到伺服器上。完了以後那一頭的人還得禮尚往來,這之間每個步驟都是我們實現低延遲的障礙,也是我們優化的方向。

比如DNS預解析、HTTP2的多路複用使用一條連線、頭部壓縮、對稱加密+非對稱加密、快取策略等等。理解這樣一個過程以後,要怎麼做就得實際動手處理問題中積累經驗啦。

雖發表於此,卻畢竟為一人之言,又是每日學有所得之筆記,內容未必詳實,看官老爺們還望海涵。

相關文章