網路相關的知識是每個前端工程師都應該具備的。很多從事前端的朋友們都沒系統學習過計算機網路和http相關內容。在沒有建立一個整體的知識體系下,會有一種一站到底答題的感覺,每個知識點都大致知道問題的答案,但總不確定,更不知道具體是怎麼回事。本文系統的梳理了與前端密切相關的網路知識。(這是我自己學習的總結,整理出的筆記,分享給大家)
本文中的程式碼演示整理在《node.js的小美好》 :
還是老規則,在學之前,我們先考考自己,我整理一下知識點,看看我們需要掌握那些問題。然後我們通過把問題知識點串起來去總結。
必會:
- http報文都有哪些內容?
- HTTP協議頭含有哪些重要的部分,HTTP狀態碼?
- HTTP狀態碼狀態碼都有哪些?
- 什麼是強快取?什麼是弱快取?
- 瀏覽器的現快取機制是什麼?如何設定HTTP快取?
- 你知道有哪些HTTP方法?POST 和 PUT 有什麼區別?
- 如何對資料進行壓縮(ZLIB),Gzip? 壓縮的範圍是什麼,請求頭會壓縮嗎?
- 跨域,為什麼JS會對跨域做出限制?如何允許跨域?
基礎:
- 影響網速的原因有哪些?網路丟包的主要原因是什麼?
- 網路體系結構的五層參考模型都是什麼?它們之間的關係是什麼?
- 我們常聽到報文、段(分組)、資料包、幀、和資料包,它們有什麼關係?
- Ajax能傳送http請求,它和http有什麼樣的關係?
- HTTP1.0 到 http1.1 解決了什麼問題?
- http2有什麼特性?
- http1.1為什麼會有隊首阻塞?
- SSL與TLS關係?HTTPS協議如何實現?
補課與擴充:(慢慢更新)
- 常用的傳輸層協議有哪些?TCP和UDP分別有什麼特點?
- 解釋一下TCP的三次握手和四次揮手?
- 為什麼說TCP可能是網路通訊的瓶頸?如何解決TCP隊首阻塞?
- 谷歌新出QUIC為什麼要基於UDP?
- QUIC有哪些新特性,解決了什麼問題?
必會是和前端工作中聯絡最緊密的http協議相關的內容。但是如果沒有網路基礎,就好像空中樓閣。無法建立起知識體系。所以本文會把必會和基礎放到一起,也就是本文的1-5章內容。
補課與擴充套件:而深入學習下一代QUIC就必須瞭解TCP和UDP的具體工作原理。所以這裡會給大家偷偷補課。一些常用的擴充內容也會放到後邊幾章。
本文會用node做程式碼演示,相關程式碼在github上。如果node基礎不好的同學,我把本章所有的程式碼整理成了一篇node的學習文件。《node.js的小美好》 。每一小節會有一些習題,用來鞏固複習,我慢慢加。
1 網路基礎
我們從第一題開始,當瀏覽器訪問www.jd.com時,我們都知道瀏覽器向伺服器傳送了http請求,會把請求報文傳送給伺服器。那麼我先粗略分析一下這個過程。
1.1 分組傳遞
瀏覽器會基於http協議產生一個http報文(訊息),然後會把這個報文拆分成不同的分組(包)。傳送到路由上。路由先進行快取,然後在根據路由錶轉發給下一個路由,直到到達伺服器。
客戶端 ---> 路由--->路由.......----> 路由--->伺服器
複製程式碼
我們為什麼不直接把訊息傳送給伺服器,為什麼一定要分包呢?
首先,路由是先快取再轉發,如果把整個報文直接發給伺服器,那麼對路由記憶體要求會非常高。另外還有一個重要的概念就是網路的頻寬,也是在鏈路上的傳輸速率,它是由單位時間內可以傳輸的資料總量決定的。而不是我們物理距離,舉個例子。
(1)基礎題 (來自《阿里技術之瞳》)
使用一輛卡車運輸n塊裝滿資料的1TB硬碟,以80km/h速度行駛1000km將資料運送到目的地,
卡車至少運送多少塊硬碟才能使傳輸速率超過1000Gbit/s?
答案:5625
解析:這個問題可以簡化成兩種方案在相同時間內兩種方案要傳輸相同的資料量。
卡車的時間為: 1000km ÷ 80Km = 12.5h
在相同時間內網路傳輸的資料量為: 12.5h * 3600s/h * 1000Gbit/s ÷ 8b/B = 5625000GB.
那麼卡車需要運輸相同的運算量,5625000GB ÷ 1000GB = 5625塊。
總結:頻寬:在鏈路上的傳輸速率(bit/sec 即 bps)
bit(位) // 1 Byte = 8 bit
複製程式碼
擴充:那麼我們現在分析一下交付時間
現在有一個5Mbits的報文,在寬頻是1Mbps,從客戶端C1 傳送到 伺服器h2,經過路由器A,B。忽略其他影響。
C1---> A ----> B ---- h2
一次報文交換交付時間:
C1---> A : 5Mbits / 1Mbps = 5s
A ---> B : 5Mbits / 1Mbps = 5s
B --->h2 : 5Mbits / 1Mbps = 5s
共15s
如果分成5000組 , 那麼每個包是1bits。
H1---> A : 1bits / 1Mbps = 1ms
當第1個到達時A時需要1ms,第2個已經出發
當第2個已經到A時,第1個已經到達B
當第5000個到達A時,第4999個到底B,其餘都到達。這時候用時5s
當第5000個到達h2時,就用時,5秒零2毫秒。
最後總結一下:
- 報文:M bits
- 鏈路寬頻:R bps
- 路由器數:n
- 分組長度:L bits
- 一次報文交換交付時間 : T = (n+1) * (M / R)
- 分組交換報文交付時間:T = M / R + nL/R
複製程式碼
所以可以看出分組交換比一次報文互動效能要好。而上面所用的時間就叫作傳輸延遲
傳輸延遲是影響網速的最主要原因,那麼還有一些影響網速的原因我們來看看:
- 排隊延時:比如當第1個到包達時A時,如果它前面已經有一些其他客戶端的包到達,那麼它就許多排隊等待。排隊所用的時間就是排隊延時。
- 結點處理延遲:排隊到了以後,結點A會對包進行一些處理,這個處理時間叫結點處理延遲,通常是毫秒級的影響非常小。
- 傳播延遲: A出發後,從A到B在鏈路上傳播還要經過一定物理距離,但傳輸的速度非常快,通常是0.7倍的光速,所用的時間叫傳播延遲。
- 丟包: 如果很多客戶端同時向A結點傳送資料包,A的快取滿了以後,對接下來的資料包,會丟棄。而這正是丟包的主要原因。
問題:現在我們粗略瞭解了這個過程,那麼具體都經歷那些過程呢?
1.2 網路體系結構
我們先看來看OSI解釋的七成參考模型。
- 分層:我們根據不同的功能把網路模型分層。
- 協議:不同層之間規定了不同協議,每個層遵循每個層的網路協議完成完成功能。
- 介面:層與層之間會通過介面去進行互動。
所以這也符合我們函式的模組化,低層函式定義好介面API,你按照函式的介面文件去呼叫依賴的函式,然後就等著讓它去處理。在實際的開發中,我們就是這麼去實現的。
每一層通過本層的協議,增加控制資訊,構造協議資料單元PUD。
應用層:
- 瀏覽器根據http協議,產生報文頭和主體
- 對並報文進行編碼,加密,壓縮。
- 將資料封裝好後,交給下一層,我們將這一層的PUD叫 報文(message)
傳輸層:
- 在瀏覽器端會將報文分組,在伺服器端會將報文重組。
- 在每個分組的頭,會加上自己協議資訊。
- 這些協議資訊主要功能是SAP定址,連線控制,流量控制,差錯控制
- 將資料封裝好後,交給下一層,我們將這一層的PUD叫 段(segment)
網路層:
- 網路層在拿個每個段後,會根據IP協議,加上自己協議資訊
- 這些協議資訊主要功能是:邏輯定址(IP地址)路由轉發。
- 將資料封裝好後,交給下一層,我們將這一層的PUD叫 資料包(datagram)
鏈路層:
- 網路層在拿個每個段後,會根據IP協議,加上自己協議資訊
- 這些協議資訊主要功能是:物理定址(MAC地址),流量控制,差錯控制,接入控制。
- 將資料封裝好後,交給下一層,我們將這一層的PUD叫 幀(frame)
物理層:
- 物理層在拿個幀後,會把它轉化成 位元(bit),就是位,二進位制編碼(一堆100111)
- 然後將這些二進位制,根據自己物理特性去表示,比如電訊號啥的。
- 然後就把它交給物理介質去傳輸啦
所以現在我們知道了,每傳送一個http請求,是針對應用層的請求和響應。應用層雖然來回只有一次。但它下面傳輸層,要把整個報文,分成許多分組,再交給下一層,著名的TCP三次連結就是指的傳輸層的。所以應用層的一次請求和響應,再鏈路是可能要走許多次。每個包肯定是肯定擁有每個層的協議,不可能只有上層沒有下層。而我們常說的資料包,就應該是一個段(分組)經過處理成,最後變成位元在鏈路上傳輸。
你會發現我們並沒有講表示層和會話層?因為
應用層 和 傳輸層 我們後邊都會詳細講。這裡我們再講一下 網路層,鏈路層,物理層。
1.3 鏈路層與物理層
上面我們知道,物理層會把位元在物理介質上傳輸。那麼主機可能和多臺電腦相連,那麼二進位制碼怎麼會知道 這是發個那臺電腦,走那條網線呢?
我們知道在鏈路層會加上要訪問主機的物理定址(MAC地址),所以如果網線連多個電腦,會送到每臺電腦,在物理層轉化回幀,發現如果不是目標電腦的Mac地址,就不去處理。直到找到目標Mac地址的電腦。這裡用到的就是MAC協議。
1.4 網路層與鏈路層
那麼鏈路層是怎麼知道目標機器的Mac地址的呢?
在網路層,我們知道了要訪問伺服器的IP,首先作業系統會判斷是不是本地IP,如果不是,會傳送給閘道器。 作業系統啟動的時候,就會被 DHCP 協議配置 IP 地址,以及預設的閘道器的 IP 地址 192.168.1.1。 作業系統會廣播,誰是 192.168.1.1 啊?閘道器會回答它,我就是,這是Mac地址。這樣我們就知道了Mac 地址。這個廣播得到Mac 地址的協議就是ARP協議。
閘道器往往是一個路由器,知道到某個 IP 地址應該怎麼走,這個叫作路由表。這樣它再從幀中取出資料包,看到了你想去的IP,它就會告訴你那你應該走那條路,並去找哪個路由。然後在鏈路層封裝的幀中寫入那個路由的Mac地址。
路由是怎麼知道怎麼走的呢,因為路由和路由也會溝通。溝通的協議稱為路由協議,常用的有OSPF和BGP。
(測試題1)不定選項 七層網路協議(來自京東2018秋招筆試題)
用瀏覽器訪問www.jd.com時,可能使用到的協議有?
A MAC
B HTTP
C SMTP
D ARP
E RTSP
答案:A B D
解析:所以在第一題中 HTTP是在應用層用的協議 。
MAC和ARP是在資料鏈路層用和網路層用到的協議。
而同樣的應用層協議SMTP是郵件傳輸協議,RTSP是實時流傳輸協議。
在訪問www.jd.com的時候,我們用不到。
複製程式碼
2 應用層
2.1 應用層協議
應用層是基於傳輸層協議之上。常見的傳輸層協議有TCP,UDP。
- 基於TCP:HTTP(超文字傳輸協議),FTP(檔案傳輸協議),SMTP(郵件傳輸協議)
- 基於UDP:DNS(域名系統)和最近興起的QUIC(谷歌制定低時延的網際網路傳輸層協議)
應用層的功能是完成客戶端和伺服器訊息交換。要想完成資訊交換就必須知道資源的位置,那我們是怎麼約定資源位置的呢。
2.2 URL:統一資源定位符
語法為:
協議://使用者名稱:密碼@子域名.域名.頂級域名:埠號/目錄/檔名.檔案字尾?引數=值#標誌
http://username:password@host:80/directory/file.html?query#ref
ftp://username:password@host:21/directory/file.html
news://news.newsgroup.com.hk
複製程式碼
注意:
如果引數裡邊有!,%,&,/,?,=,等非西歐字元 需要encode 方法對url的進行預處理
- decode解碼成普通字串
- encode普通字串編碼,編碼後的名字非常長叫(application/x-www-form-urlencoded MIME 字串)
2.3 程式碼演示
應用層的功能是完成客戶端和伺服器訊息交換。
- 瀏覽器傳送http請求:會輸入ip服務和埠
- 伺服器監聽埠號,在收到請求時作出響應的
這時我們會過頭來看,瀏覽器左下角,是不是一直在顯示等待響應,是因為我們還沒有返回資料啊,那我們給 它返回一些資料。
這裡我們先不用管TCP的細節部分,我們會在傳輸層部分去講。
問題:在大致瞭解了應用層協議後,就讓我們去具體學習http協議吧
3 HTTP協議:
這一節的內容,可是前端的看家本領,大家一定要對應著程式碼自己敲出來,看看效果
- HTTP是超文字傳輸協議,從www瀏覽器傳輸到本地瀏覽器的 一種傳輸協議,
- HTTP協議是由從客戶機到伺服器的請求(Request)和從伺服器 到客戶機的響應(response)進行約束和規範。
3.1 HTTP報文
HTTP報文:用於HTTP協議互動的資訊被稱為HTTP報文。
- 請求(Request)端的報文叫請求報文
- 響應(response)端的報文叫響應報文
我們那上一節以響應報文為例,我們之前說要符合http協議的規則,那麼http規則是什麼呢?
let responseDataTpl = `HTTP/1.1 200 OK
Connection:keep-alive
Date: ${new Date()}
Content-Length: 12
Content-Type: text/plain
Hello world!
`;
複製程式碼
- 報文首部和報文主體中間要有空行(CR+LF:回車+換行)
- 報文首部:處理請求和響應提供的資訊(上文中設定的各種資訊)
- 報文主體:所需要的資源都在(比如返回的文字資訊就是Hello world)
報文首部:根據實際用途會分為四種
- 通用首部欄位(General):請求報文和響應報文都會使用的欄位
- 請求首部欄位(Requse Header):請求報文使用的首部
- 響應首部欄位(Response Header):響應報文使用的首部
- 實體首部欄位(Entity Header):與實體有關資訊的欄位
所以在chrome的network中,header會顯示為:
- General
- Response Headers
- Requse Headers
實體首部欄位會寫進請求頭和響應頭 對於get請求後邊的引數會顯示在Query String Parameters
在上邊TCP伺服器中,我們發現每次寫符合http協議格式的響應報文非常麻煩,為什麼我們不封裝好呢?對啊,所以下面的案例我們就用了封裝好的HTTP模組。
程式碼演示:用node搭建HTTP伺服器
我們在程式碼中看到'Content-Type',它的作用是規定內容的格式。
問題:現在你把實戰中的狀態碼改成400,發現頁面仍然能正常訪問。這其實就是你和後端按照標準預定的啊,那麼是有什麼樣子的標準呢?
3.2 HTTP狀態碼
HTTP狀態碼:是客戶端向服務端傳送請求,描述請求的狀態。 狀態碼組成:以3位數字和原因短語組成 比如(200 OK 和 206 Partial Content)
第一位數字代表類別:
- 1XX : 資訊性狀態碼(接收請求正在處理)
- 2XX : 成功狀態碼(請求正常處理完畢)
- 3XX : 重定向狀態碼(需要進行附加操作以完成請求)
- 4XX : 客戶端錯誤狀態碼(伺服器無法處理請求)
- 5XX : 服務端錯誤狀態碼(伺服器處理請求出錯)
複製程式碼
所以狀態碼就是前後端通訊時對於狀態的一種約定,原則上只要遵循狀態碼類別的定義,即使改變RFC2616定義的狀態碼,或自行建立都是沒問題的。
像上面你非將200成功狀態改成400,就好比,你把紅燈換成綠燈,老司機們都會亂了套。那現在我們看看老司機們都常用的狀態碼都有哪些吧。
- 200 OK :請求被正常處理返回 200 OK,這也是我們最常見的啦
- 204 No Content :請求處理成功但是沒有資源返回,就是報文中沒有報文主體
- 206 Partial Content :客戶端進行範圍請求,就是請求資源一部分,伺服器返回請求這部分(Content-Range)
- 301 Moved Permanently:永久重定向(資源的URL已經更新)
- 302 Found :臨時重定向(資源的URI已經臨時定位到其他位置了)
- 303 See Other: 對應的資源存在另一URL,資源的URL已經更新,是否按新的去訪問
- 304 Not Modified:客戶端發附帶條件的請求,服務端允許請求訪問資源,但沒有滿足條件
- 307 Temporary Redirect: 也是臨時重定向
- 400 Bad Request : 請求報文中存在語法錯誤
- 401 Unauthorized : 需要有HTTP認證
- 403 Forbidden : 請求訪問的資源被伺服器拒絕了
- 404 Not Found : 伺服器上沒有找到資源
- 500 Internal Server Error: 伺服器執行請求時出錯
- 503 Service Unavailable : 伺服器處於超負載,正在進行停機維護
複製程式碼
程式碼演示:用url路徑模組,完成了node路由
(測試題3)單選題 http狀態碼(來自阿里技術之瞳)
chrome DevTools的Network皮膚中參看靜態資源載入情況,當發現靜態資源的HTTP狀態碼
是___時,需要使用強制重新整理以便獲得最新版的靜態資源?
A 204
B 304
C 403
D 501
答案:B
解析:304是資源重定向,客戶端發附帶條件的請求,服務端允許請求訪問資源,但沒有滿足條件
你是不是還有點蒙呢,彆著急httpd的快取協議裡你就會看見它啦。
複製程式碼
問題:我們知道了狀態碼代表的含義,但是它們在什麼場景下會出現呢?讓我們一個一個去學習吧
3.2 HTTP壓縮協議
HTTP壓縮協議理解起來很簡單,就好像你要給你朋友在QQ上傳1個1G檔案,需要10分鐘,哇網速好快哦。 但是你要是壓縮一下,這個檔案就變成了300M。再給你朋友傳可能就需要3分鐘。然後你壓縮需要1分鐘,他解壓需要一分鐘。這樣你們5分鐘就搞定啦。同樣的道理。
- http請求頭帶:Accept-Encoding: gzip, deflate, br
這是瀏覽器告訴伺服器我支援什麼樣的壓縮格式,優先順序是什麼樣的。
- http響應頭帶:Content-Encoding: gzip
這是伺服器告訴瀏覽器我已經按什麼樣子的格式壓縮了,解壓工作你拜託你了
所以在瀏覽器上我們就需要根據請求頭中的Accept-Encoding去判斷,瀏覽器支援什麼壓縮啊。然後壓縮之後再告訴瀏覽器,我已經給你壓縮成什麼樣子啦。
程式碼演示:2.5 用gzip對檔案進行壓縮
3.3 HTTP快取協議
3.3.1 強快取
Catche Contrl: :是通用首部欄位,就是之前將的傳送報文和響應報文都會使用的。可以對檔案裡引用資源的快取進行設定
這裡舉一個簡單的例子:
瀏覽器發訪問http://localhost:10080/
- '請求報文沒帶 Cache-Control' 客戶端說我要訪問首頁
伺服器返回資料
- '響應報文帶:Cache-Control : max-age = 604800' 伺服器說給你index.html和載入裡面資源,並告訴你這些資源一週之內不要不必確認了
瀏覽器重新整理的網頁再次訪問http://localhost:10080/時
- 裡面的資源就不會再傳送請求了,直接從快取中拿 你會在chrome,network中看到Time是0(from memory catch)
伺服器返回資料
- 伺服器只返回index.html檔案
這時候你強制重新整理瀏覽器(command+shift+R)
- '請求報文帶 Catche Contrl:no-cache '客戶端說我不要快取過的資料,我要源伺服器的資料
伺服器返回資料
- 伺服器返回index.html檔案和依賴的資源
複製程式碼
這就是強快取,所謂強是在條件內,你網頁依賴的資源都不會傳送http請求了。可以直接從網頁裡面拿。
程式碼演示:瀏覽器快取協議的實現
3.3.2 協商快取
有兩種:
第一種:If-Modified-Since/Last-Modified
伺服器會下發一個Last-Modified最後修改時間。然後瀏覽器會記住這個時間。當瀏覽器第二次請求時會帶上if-modified-since的時間。伺服器可以去比較這份檔案在if-modified-since的時間後是否修改過。如果沒有修改過,那就返回304.
- Last-Modified:標示這個響應資源的最後修改時間。web伺服器在響應請求時,告訴瀏覽器資源的最後修改時間。
- If-Modified-Since:當資源過期時(使用Cache-Control標識的max-age),發現資源具有Last-Modified宣告,則再次向web伺服器請求時帶上頭 If- -Modified-Since,表示請求時間。web伺服器收到請求後發現有頭If-Modified- Since 則與被請求資源的最後修改時間進行比對。若最後修改時間較新,說 明資源又被改動過,則響應整片資源內容(寫在響應訊息包體內),HTTP 200;若最後修改時間較舊,說明資源無新修改,則響應HTTP 304 (無需包 體,節省瀏覽),告知瀏覽器繼續使用所儲存的cache。
程式碼演示:瀏覽器快取協議的實現
上面那個程式碼中我們伺服器並沒有實現去記錄檔案修改時間,我們只要拿一段時間內去比較。我們知道了使用 if-modified-since,伺服器就要每次記錄檔案的一個修改時間。所以用時間去判斷並不是很好。
第二種:Etag/ If-None-Match
伺服器Etag會下發一個字串,然後瀏覽器在第二次請求時會在if-none-match中帶上這個字串。這時候伺服器可以比較兩個字串,如果相同,就讓瀏覽器去快取中去取。
- Etag:web伺服器響應請求時,告訴瀏覽器當前資源在伺服器 的唯一標識(生成規則由伺服器決定)
- If-None-Match:當資源過期時(使用Cache-Control標識的max- age),發現資源具有Etage宣告,則再次向web伺服器請求時帶 上頭If-None-Match (Etag的值)。web伺服器收到請求後發現 有頭If-None-Match 則與被請求資源的相應校驗串進行比對,決 定返回200或304。
程式碼演示:瀏覽器快取協議的實現
那麼現在在學完兩種快取之後,你會問,如果同時都有,那麼瀏覽器是如何判斷的呢?
3.3.3 瀏覽器快取機制
所以可以看出,強快取優先於協商快取。
(習題4)不定選項 HTTP快取 (來自京東2018秋招筆試題)
以下哪些是HTTP請求中瀏覽器快取機制會用到的協議頭?
A Last-Modified
B Etag
C Referer
D Authorization
答案: A B
複製程式碼
3.4 HTTP方法
post和get區別最近好像總有爭論,到底有什麼區別。既然都是應用層的協議,我們不妨迴歸到本質就看看。我們先來將一下http都有哪些方法,再說post和get的區別。
3.4.1 HTTP方法
- GET:獲取資源
- POST:傳輸實體主體
- PUT:傳輸檔案
- HEAD:獲取報文首部
- DELETE:刪除檔案
- OPTIONS:查詢支援方法
- TRACK:追蹤路徑
- CONNECT:要求用隧道協議連線代理
3.4.2 GET 與 POST區別
協議不久是規定應用層雙方的行為和約定嗎?那麼我們就分別從瀏覽器和伺服器去看看。
瀏覽器:
- GET是請求資料,使用URL或Cookie傳參。POST是傳輸實體主體所以會把引數放到報文體中
- GET資料放到URL中,瀏覽器對URL大小有限制,所以資料大小進行限制。POST是傳輸實體主體,所以大小沒有限制
- GET資料放到URL中,所以安全性肯定不高啊,所以不能用來傳遞敏感資訊。POST相對安全
- GET是請求資料所以URL地址可以後退,而POST傳送資料不會(chrome中post就會後退)。
- GET是請求所以會被瀏覽器主動cache,而POST是傳送資料,所以不會除非手動設定。
伺服器:
- get是把引數放到URL中去處理
- 而post是觸發了伺服器中監聽的請求事件,伺服器可能會做出處理,影響返回結果
這裡如果不是理解,建議先把這小節實戰程式碼看一下:2.6 瀏覽器快取協議的實現
看完服務具體是如何響應的,現在你對下面這句話是不是理解了呢?
“GET和POST最大的區別主要是GET請求是冪等性的,POST請求不是。冪等性是指一次和多次請求某一個資源應該具有同樣的副作用。簡單來說意味著對同一URL的多個請求應該返回同樣的結果。”
答了這麼多,不知道你發現沒有。瀏覽器的所有行為都是根據這兩個動作做出的相關反應啊。 那麼什麼時候使用get,什麼時候使用post?
根據協議使用啊,不都給你規定好了嗎?請求資料的時候用get,傳輸實體主體的時候用post。
問題:哈哈,學到這,你是不是漸漸明白,並找到一直學不好網路的原因了,都怪瀏覽器太智慧!對,現代瀏覽器已經非常智慧了,所以很多時候,即使的程式碼質量不高,它也能給你有很好的優化。但是我們畢竟還是要做一名合格的前端工程師,那麼下一節就讓我們走進瀏覽器吧
4 瀏覽器與協議
4.1 XHR 與 AJAX
對於前端工程師來說,AJAX再熟悉不過了,我們知道它是用來傳送http請求的。那麼它到底與http什麼關係?那我們先來手寫一個AJAX。
-
AJAX全稱是Asynchronous JavaScript and XML(非同步js和XML)。非同步js,我們比較容易理解。那麼什麼是XHR呢。
-
XHR全稱是XMLHttpRequest,就是XML的http的請求。其實這是一個瀏覽器層面的API。通俗點講就是瀏覽器給你封裝好了的http功能函式。
在之前的課程,我們傳送的http請求都是瀏覽器自己主動傳送的。如果,瀏覽器沒有開放這麼一個功能。你就當然沒有能力主動向伺服器獲取資料。所以就完不成互動。這就是為什麼在AJAX 之前要通過重新整理頁面來解決。
那麼我們如何理解XHR是瀏覽器層面的API?
-
我們在node服務端的時候知道,我們經常需要需要操作請求頭中的資料,比如根據請求頭中的壓縮機制做出相應的處理。但我們在前端用ajax得到資料的時候。並不用考慮壓縮啊,這就是因為XHR是一個瀏覽器層面的API。它向我們隱藏了大量的底層處理,比如壓縮,快取。換句話說,瀏覽器也沒有開放給你做這些事能力。
-
總結一下,其實很好理解,我們的web頁面是跑在瀏覽器上的,雖然瀏覽器是智慧的,但也是通用的,不是為我們定製的。這也正是webapp不如原生app的體驗流暢的原因啊。原聲app可以理解為(瀏覽器+頁面)。而webapp是在瀏覽器上寫內容。
但是瀏覽器單單傳送http請求的是不能滿足我們日常開發需求的。為了完成跟多的功能,我們有長輪詢,瀏覽器也提供的了websocket的API。這寫具體涉及到業務的場景的功能。有機會單寫一篇吧。
問題:我們知道了瀏覽器給我們帶來很多的限制,那麼具體業務有哪些影響呢?
4.2 瀏覽器安全與跨域
所以我們再XHR的會有很多限制,其中對我們影響很大的就是不允許傳送不同協議,地址和埠號的請求。
那麼我們常見的解決方案有三種:
- jsonp :是把請求偽裝成標籤去請求。因為標籤是瀏覽器自己傳送請求,所以不受同源策略影響啊
- 代理伺服器:這個也很好理解,我把所有請求都傳送到不跨域的代理伺服器上,伺服器上可是我們說的算,只要經過處理把資料返回給瀏覽器就好。
- CORS:這是我們今天主要講。因為解鈴還須繫鈴人,既然是你限制的,那麼你總得給我一個解決辦法吧。瀏覽器給出的解決辦法就是(CORS)
cors的辦法也很簡單:
- 如果瀏覽器發現你已經跨域了它會傳送一個帶原IP的請求頭Origin: http://localhost:8088
- 問伺服器,你讓不讓localhost:8088訪問你的檔案啊,如果瀏覽器同意就回復一個Access-Control-Allow-Origin: http://localhost:8088 。表示,這個IP可以訪問的
- 然後伺服器在發起正式請求
- 如果伺服器沒有給瀏覽器返回Access-Control-Allow-Origin或不允許這個地址訪問,那麼瀏覽器就報跨域請求錯誤
當然,為了安全起見CORS的請求都會忽略掉cookie 和 HTTP認證等使用者憑證。如果你想用,同樣在請求頭帶Origin時在傳送一些引數。伺服器也是在第一次返回時告訴瀏覽器同意還是不同意。
程式碼演示: 2.8 node處理跨域
5 http發展
5.1 HTTP1.0 到http1.1
- HTTP1.0的時候,每次傳送一個http請求就要建立一次TCP連線,然後再斷開
- http1.1的時候,引入了Connection:keep-alive的機制,連線後不斷開可以繼續傳送請求
- 但每次請求都是第一個回來,第二個再出發。後來瀏覽器又引入了 pipelining的管道化連線。
- 在一個TCP連線內,多個HTTP請求可以並行,下一個HTTP請求在上一個HTTP請求的應答完成之前就發起 這個不需要你去設定,引入了Connection:keep-alive,瀏覽器自動會這麼處理。但這又有一個問題,由於HTTP1.1服務端返回響應資料的順序必須跟客戶端請求時的順序一致,這樣也就是要求先進先出。所以很容易造成隊首阻塞。就是你第一個請求不返回,後面都得在那等著。
所以這節的重點就是http2就解決了隊首阻塞的問題。但http2是基於https的,那就讓我們先學習https吧
5.2 HTTPS
HTTPS是針對HTTP安全性不足,做的改進,我們先看看HTTP安全性都有哪些不足
- 通訊就是明文
- 沒有驗證通訊方身份
- 無法證明報文完整性
** 所以 HTTS = HTTP + 加密 + 認證 + 完整性保護 **
那麼現在我們先看看如何加密解密的吧?
-
比如我有一份資料要給你,我只需要把它加密了,你在解密這樣不就安全了。
-
所以我有一個私鑰用來加密,給別人解密的是公鑰
-
但是這個時候,我們又不能保證別人拿到的公鑰就是我的公鑰。萬一資料沒有變,但是公鑰被劫持,解密出來的內容就也不是我想發給對方的啦
-
所以我把公鑰交給第三方CA認證一下,第三方把公鑰變成了證照
-
這樣瀏覽器再拿到我發給它的證照的時候,他去和第三方CA問一下,這是不是他的證照啊。
-
第三方說是,這樣我們就安全了。
-
同樣瀏覽器也會以同樣的私鑰和證照的方式對傳給伺服器的資料進行加密解密。在第三方認證的時候,我們會詳細登記自己的資訊。這樣我們彼此也就完成了身份認證。
-
最後,這個加密演算法還用摘要功能來保證資料的完整性
現在我們知道了就是通過一個私鑰和證照對資料進行進行加解密。所以HTTPS協議只是HTTP通訊介面部分用SSL協議代替而已。而剛才我們講的這個過程就是SSL協議的內容。它是由網景公司發明,後來轉交給IETF,IETF在SSL基礎上制定的TLS(改個名字)。
程式碼演示:3.1 https的node伺服器的搭建
5.2 HTTP2.0
現在終於來到我們http2啦。還記得我們說的http1.1的對手阻塞嘛。對http2就解決了這個問題。
- (1)多路複用,並不在遵循先進先出。
那麼現在有一個問題,http2中,既然沒有先進先出,那麼重要的檔案載入的慢,那不就尷尬啦。
- (2)http2定義了請求優先順序
我們可以讓一些重要的請求優先載入。瀏覽器也智慧的根據http2定義出的優先順序規則去顯示頁面。
- (3)頭部壓縮
我們知道我們在用Gzip方式給報文體進行壓縮。http2給報文頭也進行了壓縮。你可別小看了報文頭,一般網頁的報文頭能佔到報文的40%。 而壓縮後能減少60%左右。
- (4)效能上新增了二進位制分幀層。也得到了大大的提升。分針層對應的就是http報文。所以http/1.1是一個文字協議,而 http2 是一個徹徹底底的二進位制協議。
接下來就讓我們動手去實踐一下吧。
最後,寫的好累。。。覺得這一篇寫不完。後邊寫的太糙了。我慢慢改改。擴充有空在寫吧。