字節(jié)跳動最愛考的前端面試題:計算機網(wǎng)絡基礎
注意:每道題前面出現(xiàn)的 (xx) 數(shù)字代表這道題出現(xiàn)的頻次,此 計算機網(wǎng)絡 基礎是基于 30+ 篇前端面經整理出的問題和對應的回答、參考鏈接等。文章內容為拿到 Offer 的本人整理。
(3)問:HTTP 緩存
HTTP 緩存又分為強緩存和協(xié)商緩存:
- 首先通過 Cache-Control 驗證強緩存是否可用,如果強緩存可用,那么直接讀取緩存
- 如果不可以,那么進入?yún)f(xié)商緩存階段,發(fā)起 HTTP 請求,服務器通過請求頭中是否帶上 If-Modified-Since 和 If-None-Match 這些條件請求字段檢查資源是否更新:
- 若資源更新,那么返回資源和 200 狀態(tài)碼
- 如果資源未更新,那么告訴瀏覽器直接使用緩存獲取資源
(5)問:HTTP 常用的狀態(tài)碼及使用場景?
- 1xx:表示目前是協(xié)議的中間狀態(tài),還需要后續(xù)請求
- 2xx:表示請求成功
- 3xx:表示重定向狀態(tài),需要重新請求
- 4xx:表示請求報文錯誤
- 5xx:服務器端錯誤
常用狀態(tài)碼:
- 101 切換請求協(xié)議,從 HTTP 切換到 WebSocket
- 200 請求成功,有響應體
- 301 永久重定向:會緩存
- 302 臨時重定向:不會緩存
- 304 協(xié)商緩存命中
- 403 服務器禁止訪問
- 404 資源未找到
- 400 請求錯誤
- 500 服務器端錯誤
- 503 服務器繁忙
你知道 302 狀態(tài)碼是什么嘛?你平時瀏覽網(wǎng)頁的過程中遇到過哪些 302 的場景?
而 302 表示臨時重定向,這個資源只是暫時不能被訪問了,但是之后過一段時間還是可以繼續(xù)訪問,一般是訪問某個網(wǎng)站的資源需要權限時,會需要用戶去登錄,跳轉到登錄頁面之后登錄之后,還可以繼續(xù)訪問。
301 類似,都會跳轉到一個新的網(wǎng)站,但是 301 代表訪問的地址的資源被永久移除了,以后都不應該訪問這個地址,搜索引擎抓取的時候也會用新的地址替換這個老的??梢栽诜祷氐捻憫?location 首部去獲取到返回的地址。301 的場景如下:
- 比如從 http://baidu.com,跳轉到 https://baidu.com
- 域名換了
(2)問:HTTP 常用的請求方式,區(qū)別和用途?
http/1.1 規(guī)定如下請求方法:
- GET:通用獲取數(shù)據(jù)
- HEAD:獲取資源的元信息
- POST:提交數(shù)據(jù)
- PUT:修改數(shù)據(jù)
- DELETE:刪除數(shù)據(jù)
- CONNECT:建立連接隧道,用于代理服務器
- OPTIONS:列出可對資源實行的請求方法,常用于跨域
- TRACE:追蹤請求-響應的傳輸路徑
()問:你對計算機網(wǎng)絡的認識怎么樣
應用層、表示層、會話層、傳輸層、網(wǎng)絡層、數(shù)據(jù)鏈路層、物理層
(3)問:HTTPS 是什么?具體流程
HTTPS 是在 HTTP 和 TCP 之間建立了一個安全層,HTTP 與 TCP 通信的時候,必須先進過一個安全層,對數(shù)據(jù)包進行加密,然后將加密后的數(shù)據(jù)包傳送給 TCP,相應的 TCP 必須將數(shù)據(jù)包解密,才能傳給上面的 HTTP。
瀏覽器傳輸一個 client_random 和加密方法列表,服務器收到后,傳給瀏覽器一個 server_random、加密方法列表和數(shù)字證書(包含了公鑰),然后瀏覽器對數(shù)字證書進行合法驗證,如果驗證通過,則生成一個 pre_random,然后用公鑰加密傳給服務器,服務器用 client_random、server_random 和 pre_random ,使用公鑰加密生成 secret,然后之后的傳輸使用這個 secret 作為秘鑰來進行數(shù)據(jù)的加解密。
(4)問:三次握手和四次揮手
為什么要進行三次握手:為了確認對方的發(fā)送和接收能力。
三次握手
三次握手主要流程:
- 一開始雙方處于 CLOSED 狀態(tài),然后服務端開始監(jiān)聽某個端口進入 LISTEN 狀態(tài)
- 然后客戶端主動發(fā)起連接,發(fā)送 SYN,然后自己變?yōu)?SYN-SENT,seq = x
- 服務端收到之后,返回 SYN seq = y 和 ACK ack = x + 1(對于客戶端發(fā)來的 SYN),自己變成 SYN-REVD
- 之后客戶端再次發(fā)送 ACK seq = x + 1, ack = y + 1給服務端,自己變成 EASTABLISHED 狀態(tài),服務端收到 ACK,也進入 ESTABLISHED
SYN 需要對端確認,所以 ACK 的序列化要加一,凡是需要對端確認的,一點要消耗 TCP 報文的序列化
為什么不是兩次?
無法確認客戶端的接收能力。
如果首先客戶端發(fā)送了 SYN 報文,但是滯留在網(wǎng)絡中,TCP 以為丟包了,然后重傳,兩次握手建立了連接。
等到客戶端關閉連接了。但是之后這個包如果到達了服務端,那么服務端接收到了,然后發(fā)送相應的數(shù)據(jù)表,就建立了鏈接,但是此時客戶端已經關閉連接了,所以帶來了鏈接資源的浪費。
為什么不是四次?
四次以上都可以,只不過 三次就夠了
四次揮手
- 一開始都處于 ESTABLISH 狀態(tài),然后客戶端發(fā)送 FIN 報文,帶上 seq = p,狀態(tài)變?yōu)?FIN-WAIT-1
- 服務端收到之后,發(fā)送 ACK 確認,ack = p + 1,然后進入 CLOSE-WAIT 狀態(tài)
- 客戶端收到之后進入 FIN-WAIT-2 狀態(tài)
- 過了一會等數(shù)據(jù)處理完,再次發(fā)送 FIN、ACK,seq = q,ack = p + 1,進入 LAST-ACK 階段
- 客戶端收到 FIN 之后,客戶端收到之后進入 TIME_WAIT(等待 2MSL),然后發(fā)送 ACK 給服務端 ack = 1 + 1
- 服務端收到之后進入 CLOSED 狀態(tài)
客戶端這個時候還需要等待兩次 MSL 之后,如果沒有收到服務端的重發(fā)請求,就表明 ACK 成功到達,揮手結束,客戶端變?yōu)?CLOSED 狀態(tài),否則進行 ACK 重發(fā)
為什么需要等待 2MSL(Maximum Segement Lifetime):
因為如果不等待的話,如果服務端還有很多數(shù)據(jù)包要給客戶端發(fā),且此時客戶端端口被新應用占據(jù),那么就會接收到無用的數(shù)據(jù)包,造成數(shù)據(jù)包混亂,所以說最保險的方法就是等服務器發(fā)來的數(shù)據(jù)包都死翹翹了再啟動新應用。
- 1個 MSL 保證四次揮手中主動關閉方最后的 ACK 報文能最終到達對端
- 1個 MSL 保證對端沒有收到 ACK 那么進行重傳的 FIN 報文能夠到達
為什么是四次而不是三次?
** 如果是三次的話,那么服務端的 ACK 和 FIN 合成一個揮手,那么長時間的延遲可能讓 TCP 一位 FIN 沒有達到服務器端,然后讓客戶的不斷的重發(fā) FIN
參考資料
https://zhuanlan.zhihu.com/p/86426969
問:在交互過程中如果數(shù)據(jù)傳送完了,還不想斷開連接怎么辦,怎么維持?
在 HTTP 中響應體的 Connection 字段指定為 keep-alive
你對 TCP 滑動窗口有了解嗎?
在 TCP 鏈接中,對于發(fā)送端和接收端而言,TCP 需要把發(fā)送的數(shù)據(jù)放到發(fā)送緩存區(qū), 將接收的數(shù)據(jù)放到接收緩存區(qū)。而經常會存在發(fā)送端發(fā)送過多,而接收端無法消化的情況,所以就需要流量控制,就是在通過接收緩存區(qū)的大小,控制發(fā)送端的發(fā)送。如果對方的接收緩存區(qū)滿了,就不能再繼續(xù)發(fā)送了。而這種流量控制的過程就需要在發(fā)送端維護一個發(fā)送窗口,在接收端維持一個接收窗口。
TCP 滑動窗口分為兩種: 發(fā)送窗口和接收窗口。
參考資料
https://juejin.im/post/5e527c58e51d4526c654bf41#heading-38
問:WebSocket與Ajax的區(qū)別
本質不同
Ajax 即異步 JavaScript 和 XML,是一種創(chuàng)建交互式網(wǎng)頁的應用的網(wǎng)頁開發(fā)技術
websocket 是 HTML5 的一種新協(xié)議,實現(xiàn)了瀏覽器和服務器的實時通信
生命周期不同:
- websocket 是長連接,會話一直保持
- ajax 發(fā)送接收之后就會斷開
適用范圍:
- websocket 用于前后端實時交互數(shù)據(jù)
- ajax 非實時
發(fā)起人:
- AJAX 客戶端發(fā)起
- WebSocket 服務器端和客戶端相互推送
了解 WebSocket嗎?
長輪詢和短輪詢,WebSocket 是長輪詢。
具體比如在一個電商場景,商品的庫存可能會變化,所以需要及時反映給用戶,所以客戶端會不停的發(fā)請求,然后服務器端會不停的去查變化,不管變不變,都返回,這個是短輪詢。
而長輪詢則表現(xiàn)為如果沒有變,就不返回,而是等待變或者超時(一般是十幾秒)才返回,如果沒有返回,客戶端也不需要一直發(fā)請求,所以減少了雙方的壓力。
參考鏈接
https://www.jianshu.com/p/3fc3646fad80
HTTP 如何實現(xiàn)長連接?在什么時候會超時?
通過在頭部(請求和響應頭)設置 Connection: keep-alive,HTTP1.0協(xié)議支持,但是默認關閉,從HTTP1.1協(xié)議以后,連接默認都是長連接
- HTTP 一般會有 httpd 守護進程,里面可以設置 keep-alive timeout,當 tcp 鏈接閑置超過這個時間就會關閉,也可以在 HTTP 的 header 里面設置超時時間
- TCP 的 keep-alive 包含三個參數(shù),支持在系統(tǒng)內核的 net.ipv4 里面設置:當 TCP 鏈接之后,閑置了 tcp_keepalive_time,則會發(fā)生偵測包,如果沒有收到對方的 ACK,那么會每隔 tcp_keepalive_intvl 再發(fā)一次,直到發(fā)送了 tcp_keepalive_probes,就會丟棄該鏈接。
- tcp_keepalive_intvl = 15
- tcp_keepalive_probes = 5
- tcp_keepalive_time = 1800
實際上 HTTP 沒有長短鏈接,只有 TCP 有,TCP 長連接可以復用一個 TCP 鏈接來發(fā)起多次 HTTP 請求,這樣可以減少資源消耗,比如一次請求 HTML,可能還需要請求后續(xù)的 JS/CSS/圖片等
參考鏈接
https://blog.csdn.net/weixin_37672169/article/details/80283935
https://www.jianshu.com/p/3fc3646fad80
問:Fetch API與傳統(tǒng)Request的區(qū)別
- fetch 符合關注點分離,使用 Promise,API 更加豐富,支持 Async/Await
- 語意簡單,更加語意化
- 可以使用 isomorphic-fetch ,同構方便
參考資源
https://github.com/camsong/blog/issues/2
(2)問:POST一般可以發(fā)送什么類型的文件,數(shù)據(jù)處理的問題
- 文本、圖片、視頻、音頻等都可以
- text/image/audio/ 或 application/json 等
問:TCP 如何保證有效傳輸及擁塞控制原理。
- tcp 是面向連接的、可靠的、傳輸層通信協(xié)議
- 可靠體現(xiàn)在:有狀態(tài)、可控制
- 有狀態(tài)是指 TCP 會確認發(fā)送了哪些報文,接收方受到了哪些報文,哪些沒有收到,保證數(shù)據(jù)包按序到達,不允許有差錯
- 可控制的是指,如果出現(xiàn)丟包或者網(wǎng)絡狀況不佳,則會跳轉自己的行為,減少發(fā)送的速度或者重發(fā)
所以上面能保證數(shù)據(jù)包的有效傳輸。
擁塞控制原理
原因是有可能整個網(wǎng)絡環(huán)境特別差,容易丟包,那么發(fā)送端就應該注意了。
主要用三種方法:
- 慢啟動閾值 + 擁塞避免
- 快速重傳
- 快速回復
慢啟動閾值 + 擁塞避免
對于擁塞控制來說,TCP 主要維護兩個核心狀態(tài):
- 擁塞窗口(cwnd)
- 慢啟動閾值(ssthresh)
在發(fā)送端使用擁塞窗口來控制發(fā)送窗口的大小。
然后采用一種比較保守的慢啟動算法來慢慢適應這個網(wǎng)絡,在開始傳輸?shù)囊欢螘r間,發(fā)送端和接收端會首先通過三次握手建立連接,確定各自接收窗口大小,然后初始化雙方的擁塞窗口,接著每經過一輪 RTT(收發(fā)時延),擁塞窗口大小翻倍,直到達到慢啟動閾值。
然后開始進行擁塞避免,擁塞避免具體的做法就是之前每一輪 RTT,擁塞窗口翻倍,現(xiàn)在每一輪就加一個。
快速重傳
在 TCP 傳輸過程中,如果發(fā)生了丟包,接收端就會發(fā)送之前重復 ACK,比如 第 5 個包丟了,6、7 達到,然后接收端會為 5,6,7 都發(fā)送第四個包的 ACK,這個時候發(fā)送端受到了 3 個重復的 ACK,意識到丟包了,就會馬上進行重傳,而不用等到 RTO (超時重傳的時間)
選擇性重傳:報文首部可選性中加入 SACK 屬性,通過 left edge 和 right edge 標志那些包到了,然后重傳沒到的包
快速恢復
如果發(fā)送端收到了 3 個重復的 ACK,發(fā)現(xiàn)了丟包,覺得現(xiàn)在的網(wǎng)絡狀況已經進入擁塞狀態(tài)了,那么就會進入快速恢復階段:
- 會將擁塞閾值降低為 擁塞窗口的一半
- 然后擁塞窗口大小變?yōu)閾砣撝?/li>
- 接著 擁塞窗口再進行線性增加,以適應網(wǎng)絡狀況
問:OPTION是干啥的?舉個用到OPTION的例子?
旨在發(fā)送一種探測請求,以確定針對某個目標地址的請求必須具有怎么樣的約束,然后根據(jù)約束發(fā)送真正的請求。
比如針對跨域資源的預檢,就是采用 HTTP 的 OPTIONS 方法先發(fā)送的。用來處理跨域請求
問:http知道嘛?哪一層的協(xié)議?(應用層)
- 靈活可擴展,除了規(guī)定空格分隔單詞,換行分隔字段以外,其他都沒有限制,不僅僅可以傳輸文本,還可以傳輸圖片、視頻等任意資源
- 可靠傳輸,基于 TCP/IP 所以繼承了這一特性
- 請求-應答,有來有回
- 無狀態(tài),每次 HTTP 請求都是獨立的,無關的、默認不需要保存上下文信息
缺點:
- 明文傳輸不安全
- 復用一個 TCP 鏈接,會發(fā)生對頭擁塞
- 無狀態(tài)在長連接場景中,需要保存大量上下文,以避免傳輸大量重復的信息
問:OSI七層模型和TCP/IP四層模型
- 應用層
- 表示層
- 會話層
- 傳輸層
- 網(wǎng)絡層
- 數(shù)據(jù)鏈路層
- 物理層
TCP/IP 四層概念:
- 應用層:應用層、表示層、會話層:HTTP
- 傳輸層:傳輸層:TCP/UDP
- 網(wǎng)絡層:網(wǎng)絡層:IP
- 數(shù)據(jù)鏈路層:數(shù)據(jù)鏈路層、物理層
(3)問:TCP 協(xié)議怎么保證可靠的,UDP 為什么不可靠?
- TCP 是面向連接的、可靠的、傳輸層通信協(xié)議
- UDP 是無連接的傳輸層通信協(xié)議,繼承 IP 特性,基于數(shù)據(jù)報
為什么 TCP 可靠?TCP 的可靠性體現(xiàn)在有狀態(tài)和控制
- 會精準記錄那些數(shù)據(jù)發(fā)送了,那些數(shù)據(jù)被對方接收了,那些沒有被接收,而且保證數(shù)據(jù)包按序到達,不允許半點差錯,這就是有狀態(tài)
- 當意識到丟包了或者網(wǎng)絡環(huán)境不佳,TCP 會根據(jù)具體情況調整自己的行為,控制自己的發(fā)送速度或者重發(fā),這是可控制的
反之 UDP 就是無狀態(tài)的和不可控制的
HTTP 2 改進
改進性能:
- 頭部壓縮
- 多路信道復用
- Server Push
參考資料https://juejin.im/post/5d032b77e51d45777a126183