前言
餘為前端菜鳥,感姿勢水平匱乏,難觀前端之大局。遂決定循前端知識之脈絡,以興趣為引,輔以幾分堅持,望於己能解惑致知、於同道能助力一二,豈不美哉。
本系列程式碼及文件均在 此處
網路層級
-
實體層(物理層):連線計算機(光纖、電纜線、無線電波、雙絞線等)。
-
連結層(資料鏈路層):確定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等)
使用者角度
-
網路通訊是主機間資料包交換,要交換資料需要知道雙方的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
基礎
應用層協議,無狀態。
-
請求/響應模型
客戶端向服務端傳送請求,服務端根據接收到的請求,處理後向客戶端返回響應資訊。
-
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協議,後續會談到
-
快取控制
-
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
圖解
HTTPS執行在SSL/TLS上,SSL/TLS執行在TCP上,所有傳輸內容都是需要加密的,可以有效防劫持
握手階段:
- 客戶端給出協議版本、客戶端生成的隨機數、支援的加密方法
- 服務端收到後確認加密方法,返回數字證書,以及一個服務端生成的隨機數
- 客戶端確認證書有效,生成一個隨機數,用證書彙總的公鑰加密隨機數,傳送給服務端
- 服務端使用私鑰獲得客戶端傳送的隨機數
- 根據約定的加密演算法,使用前面的三個隨機數生成會話金鑰,用來加密後續整個會話過程
加密解密
- 公鑰和私鑰只用於加密/解密 對話金鑰(非對稱)
- 安全與否取決於三個隨機數中的第三個能否被破解
對稱加密/非對稱加密
- 使用一對金鑰,公鑰用來加密,私鑰不公開,用於解密,慢,但是更安全 —-> 非對稱加密
- 金鑰在網路中傳輸,快但是不安全 —-> 對稱加密
- 解決:用非對稱加密的公鑰加密對稱加密的金鑰,接收方用私鑰解密得到對稱金鑰,用於加密資訊(減少複雜度,降低伺服器壓力)
升級至HTTPS
-
github免費的github pages用來搭建個人部落格非常方便,感興趣的可以參考這裡
在專案設定下選擇開啟HTTPS即可
小綠鎖很醒目
-
個人站點升級HTTPS
-
從域名服務商獲取免費的SSL證書
按照流程填寫
-
下載證書到伺服器(我的是一年免費的谷歌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,稍稍等待訪問個人網站
-
HTTP2
SPDY
SPDY與HTTP2區別在於前者強制使用SSL傳輸協議,以及兩者在首部演算法上有所區別,SPDY出現於HTTP2前,特點與HTTP2類似:多路複用、伺服器推送、頭部壓縮等。這裡暫不討論。
核心——二進位制分幀
- HTTP2採用完全二進位制的格式傳輸資料。二進位制資料在網路中傳輸單位一般為幀
- 一個幀包含有:型別Type、長度Length、標記Flag、流標識Stream和Frame payload(幀有效載荷)
- 多個幀形成幀的傳輸網路流,可以認為HTTP2是流式傳輸。
- 不改變HTTP的語義,方法、首部、動詞都不受影響
- 在應用層(HTTP2.0)和傳輸層(TCP)之間多了一個二進位制分幀層
- 將請求的內容分割為幀,頭部資訊放入headers幀,body放入data幀
- HTTP2.0所有的通訊都在一個連線上完成,每個資料流以訊息形式傳送,一個訊息包含一個或多個幀,可以亂序,到達目的地後根據幀首部的流識別符號重組
首部壓縮
- 客戶端和伺服器端使用“首部表”來跟蹤和儲存之前傳送的鍵-值對
- 如果首部不發生變化,那麼首部0開銷,此時首部自動使用之前請求的首部
- 如果發生變化,只需要將變化的部分填入首部,同時更新兩端維護的首部表即可
- 於是,並不會有分幀後多加了很多首部幀帶來的效能問題,反而提升了效能
- 合併資源減少請求並不適用與HTTP2,因為都在一個連線上
雙向並行
不需要域名分割槽,因為不限制,而且可以雙向並行多個請求/響應
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的連線情況
思考
我們說一個網頁的效能多好,最直接的一個表現是從enter敲下到頁面展示花的時間多短,也就是我們追求的低延遲高頻寬。頻寬隨著網路基礎建設不斷提高,所以效能瓶頸主要在於低延遲的難實現。
想想看,我們又要DNS解析,又要建立連線,還要加密解密,歷經千難萬險才能把請求資訊送到伺服器上。完了以後那一頭的人還得禮尚往來,這之間每個步驟都是我們實現低延遲的障礙,也是我們優化的方向。
比如DNS預解析、HTTP2的多路複用使用一條連線、頭部壓縮、對稱加密+非對稱加密、快取策略等等。理解這樣一個過程以後,要怎麼做就得實際動手處理問題中積累經驗啦。
雖發表於此,卻畢竟為一人之言,又是每日學有所得之筆記,內容未必詳實,看官老爺們還望海涵。