本文約6000餘字,閱讀需要10分鐘左右。
寫在最前
有人說,前端工程師的網路基礎很弱,說很多都是非計算機的,門檻低,其實不能一概而論。但是既然人家吐槽了,那我們就提高自己唄。
沒有規矩,不成方圓
前端工程師對這句話應該有比較深刻的感受吧,這也可能是前端變化真的太 TM
的快了。但變化的這麼快,總是要沉澱下來一些 規矩 吧,不然的話還能不能過了。
那沉澱下來的規矩在哪呢?
規矩有很多,比如:AMD
,CMD
、Promise
等,都可以看做是一種 規矩 ,下文統一叫標準吧。
有句話是這樣說的:
可以隨便造庫,但是不要隨便定標準。
也就是說,如果沒有足夠多的人達成共識的話,那麼你造的標準其實並沒有什麼卵用。
所以,靜下來想一下,我們從哲學的角度看:
如果沒有標準,那麼這個世界將會變的非常無序和混亂,正因為有了標準,世界才變的有序整齊。
對此我們可以類比資料歸納法進行推導一下:
我們將世界的網路( Internet
——國際網際網路),進行歸納,得出一個結論,如果世界上的網路沒有約定標準的話,那也將會變的異常混亂。
所以,我們學習網路基礎,其實就是在學習當今 Internet
的標準。當我們學會了標準後,我們就可以遵循它,然後去做一些我們想實現的東西。其實,你會發現,很多東西,都是這個道理。
now,我們應該就知道要怎麼去提高我們的網路基礎了。
我們要去學習 Internet
的標準,看看它的標準是什麼,為什麼要這樣去設計標準,以及這樣寫的好處是什麼,還有這樣設計的程式設計思想是什麼。
程式設計思想有時候會給我們帶來很多不一樣的感受。
為什麼現在有 MVP
、MVVM
、MVX
等設計模式。那是因為優秀的程式設計師,去學習 MVC
的經典設計思想後,得到靈感,然後將一個經典設計思想,擴充套件出很多更加優秀的設計思想。所以,這也是我們去學習一個東西的目的,也是一個能夠使我們形成一種自我驅動的一種學習模式。只有這樣,我們才能不斷進步吧。
好了,不胡扯了,那下面我就開始以我個人的學習和見解,去闡述一下 網路基礎 。
PS:Promise
有 PromiseA/B/C/
等等社群標準,但是最終選擇了 PromiseA+
作為官方標準。
Internet
並不神祕
Internet
真的並不神祕,且聽我說:
想上網,首先你得有網路裝置吧,這裡不一定是要你去買,可能是別人給你提供好了,比如運營商拉線子過來了,你就不用買線子了丫(手動滑稽),還有主機、交換機、路由器等,這些基本組成了 Internet
的網路裝置。
可能一些人不理解每個裝置的作用,但是有一些東西,當你不瞭解的時候,就嘗試使用 代入法 去理解。比如,可能對交換機和路由器不瞭解,但是不去了解,又會對後面的瞭解造成障礙,那麼怎麼辦呢?
我們可以把硬體裝置當成軟體看待
畢竟硬體裡面也是有編的程式碼丫,當然有些沒有程式碼,比如線子,集線器,但是我們可以認為裡面寫了個空函式啊,那這樣就可以從軟體層面理解硬體了。
那再可愛一點:
我們可以把完成特定功能的硬體看成是軟體中的功能模組,有入參,有出參。
再形象點,可以理解成中介軟體
資料就是在一個個中介軟體中進行傳輸,並且在每個中介軟體中做相應的處理,比如封裝,驗證正確性,最後資料展示在了你的眼睛裡。
如果這樣去理解,是不是感覺沒有想象中的深奧難懂了呢。
其實我們的目的就是:
把抽象深奧的知識形象化,然後把形象化的知識抽象成我們能理解的樣子。
這樣我們就好像讓我們可愛的腦子完成了一次 babel
轉譯,真是有趣,這是一個快速理解深奧知識的一個技巧。知識不能學死了,萬變不離其宗,很多地方都是一樣的思想,學會融會貫通是一種很重要的能力。
一道經典題引發的聯想
你能說說三次握手,四次揮手的過程嗎?
相信很多人都會被問到過,這是在考察網路知識的情況下,基本少不掉的問題,也說明了這個問題所體現的知識是基礎的,是在考察你的網路基礎。
現在當我們再次看到這個問題,我們可以嘗試向上溯源一下。比如,想一下為什麼要有這個過程,為什麼要這樣去做,我兩次握手解決不行嗎,我不做第四次揮手不可以嗎?
這裡有一篇個人認為還不錯的文章:
關於三次握手和四次揮手的回答我就不回答了,上面文章已經介紹了比較清楚了。有啥疑問,可以文末掃我微信二維碼,我們私聊交流一波( 滑稽臉 )。
資料和電的故事
這是我胡謅的一個故事:
將資料從一個主機 [北京] 傳輸到另一個主機 [南京] 是一個複雜的過程,不像是輸電那樣,一股腦輸過來就好了,當然輸電也是一門高學問,比如高壓輸電。
但是資料這東西比起電,可複雜多了。
比如,電是中央空調,誰掏錢,我就流向誰,大家都一樣,沒有什麼。基本不會存在像:你這家電好可愛哦,你家的電比我家的電帥多了的這些情況?。通過這個小栗子,我主要想說明電沒有隱私,不具有讓使用者損失什麼東西的可能。今晚電壓低了,忍一忍,明天換個大的變壓器,晚上就正常了,使用者也不會說什麼。
相比之下,資料可不一樣了,資料是一種具有隱私性質的資訊,既然具有隱私,那就得保證安全性和完整性,而且不能時而安全,時而不安全,時而完整,時而不完整,所以一下就大大提高了傳輸的複雜程度。
一張圖引發的聯想
下面我們看一張圖:
首先這張圖展示了目前整個 Internet
的層級結構。我現在也不解釋為什麼是這樣的,因為這是標準,已達成共識。但是我想說幾個情況。
第一個情況:你肯定不止一次看到過這種圖,但是很多人還是會在面試的時候被問倒,一時想不起來,這種情況的原因,基本是當初沒有理解,或者沒有進行形象化的記憶。比如一個血淋淋的事實,就是英語單詞背了那麼多,還是很快就忘。那麼現在,我們再看到這個圖時,怎麼保證下一次不再被問倒了呢?
那就要從記憶學上做文章了,要聯想,要有故事參與進來,帶劇情的那種。OK
,那現在,我們從這張圖能聯想到什麼?這是一個問題,那麼跟著我開始聯想吧。
第一個角度
從前端角度來聯想,OSI
七層模型到 TCP/IP
四層模型的轉換過程中,很明顯是做了封裝了。
從中介軟體的角度來思考,這 7
層或者 4
層,我們都可以把每一層看做是中介軟體。資料在中介軟體之間進行流動,那麼每一次經過一箇中介軟體,也就意味著會進行一次資料處理。每個中介軟體完成一個特定的功能。 TCP/IP
的四層是將七層的模型包裝了一下,化繁為簡的哲學。將功能重複性的層合併在同一層,有利於確保每一層的功能相對獨立,屬於更高階別的抽象。隱藏了細節,同時層級之間的功能區別更加明顯。
第二個角度
可以從 npm
包的角度來思考,你會發現在 TCP/IP
分層結構中,高層級會依賴低層級。就好像是 npm
包,安裝 A
包,你會自動安裝 B
包,B
包又會依賴 C
包。也就是,要想安裝成功 A
包,那麼 B
包, C
包都要參與。OK,那這樣理解的話,我應用層發起的資料流動,一定會依賴傳輸層,網路層,介面層。所以一些前端工程師只知道發起 ajax
或者 fetch
請求的時候,走了下 http
。對於走不走 tcp
, ip
,介面層。不太清楚。所以,看到這裡,我覺得小夥伴還是要好好理解一下你發起的資料請求是如何在網路中進行流動的。
HTTP/TCP/IP 三者的聯絡
三者有什麼聯絡,這裡我舉個例子,雖然不能算準確,但足夠形象。
IP
是以主機為單位,通過 IP
能找到你所在的城市。
TCP
是以主機的埠為單位,通過 TCP
能找到你所在城市的你居住的小區。
HTTP
呢,它是以使用者程式為單位,通過 HTTP
能找到你所在城市所在小區的房間號。
通過上面的比喻,是不是發現非常通俗易懂,這就是講故事的魅力,哈哈哈。這個例子也能說明,如果你想找到房間號,那你肯定是要先找到城市,然後再找到小區,最後找到房間號。也就是說你想傳送 HTTP
成功的話,那必須是 TCP
, IP
都要成功,你才能傳送 HTTP
成功。
2019年2月3號備註:上面這個 HTTP/TCP/IP 三者的聯絡
的例子舉的很不準確,在此表示道歉。
已有大佬和我進行了交流:
上圖已經給出了正確的解釋,主要原因是我強行故事了一波,導致有點本末倒置,而且還容易誤導小夥伴,道歉道歉?。
IP
IP
層是網路層,定義了不同主機之間的定址方式。簡單點理解,就是通過 IP
地址來找到對應的主機。
TCP/UDP
傳輸層是非常重要的一層,具有承上啟下,向上對應用層提供通訊服務,向下將應用層資訊封裝為網路資訊。
傳輸層連線主機之間的程式,同一主機中不同程式的網路通訊通過埠進行區分,所以傳輸層為主機提供的是埠對埠的服務。
這裡提一下,程式是什麼
可以這樣理解,當應用程式被調入記憶體執行後,這個應用程式就可以被稱為程式了。
埠不屬於任何應用程式
應用程式通過系統呼叫與某個埠建立連線( Binding
)後,才會確定這個埠是為這個程式服務的,資料什麼的都是通過埠來傳輸給程式的。因為埠不屬於任何應用程式,只是在繫結的時候,才會確定為哪個程式服務。
傳輸層和埠的互動方式
傳輸層傳給該埠的資料都被相應的程式所接收,相應的程式發給傳輸層的資料都從該埠發出。這裡的埠是傳輸層的定址方式。
埠是軟體級的概念
埠是由 16 位二進位制數來表示的正整數,也就意味著一個主機理論上最多有 65535 個傳輸層通道。但是通常都少於 65535 個。
比如說,80 埠,21 埠,8080 埠等,都是預設的埠號,通過這些埠號來完成特定的通訊。
HTTP
HTTP
是構建在 TCP/IP
之上的應用層協議,而 HTTPS
是在 HTTP
之下加入 SSL/TLS
。
簡單介紹下,HTTP
是超文字傳輸協議的英文縮寫,它是 Internet
上最主要的 Web
應用層標準,HTTP
能夠傳輸任何格式的資料。
作為前端工程師,我們應該從
HTTP
裡學習到什麼呢?
我們說一個事情,比如面試經常問你,輸入一個 url
後,會發生什麼,其實如果你理解的比較深的話,完全可以畫個圖告訴他,當然打電話就只能口述了。
- 首先你點選一個
url
,是發起了一次http
請求 http
請求一定會依賴tcp
,ip
等。也就是意味著你要做tcp
建連,IP
查詢。- 如果你的
url
是域名的話,還需要先去解析域名,也就是dns
操作。使其變成ip
地址。這個過程一定是在應用層完成的,因為應用層不完成的話,那TCP
層就拿不到IP
地址,那IP
也就收不到地址資料。所以我們這樣一推導,也就這知道了dns
是在應用層完成的。 - 資料正常傳到介面層後,肯定是要傳到對應
IP
地址的伺服器的對應埠。也就是TCP
建聯。TCP
要先建連成功,HTTP
才能進行傳輸。因為是依賴關係,接收方的HTTP
需要從TCP
那獲取資料。如果TCP
建連失敗,那HTTP
也就不可能建聯成功。 - 如果都成功了,那就傳輸資料吧。
- 傳輸完,
TCP
連線關閉。頁面有了新的資料展示在使用者的面前
看到這,你肯定會想,快取呢,這裡我沒有把快取考慮進去,今晚快取無處不在,快取這個點大家自行填充吧。
下面可以用一張很酷的圖,展示當輸入 URL
時,整個過程是什麼樣子的。如下圖所示:
HTTP
是一種標準,他有自己的形式,你看看 HTTP
的資料傳輸形式,你大概就能想象到 TCP
大概是什麼樣子的資料傳輸形式了。
網路請求的資料結構是前端控制的,比如請求的方法,請求的 url
,請求的引數等。那麼響應的資料結構就應該是由服務端來控制了,服務端給我們必要的返回資訊,比如狀態碼,資料,快取控制等。
HTTP狀態碼
在 web
程式設計中,狀態碼是非常重要的事情。
設定狀態碼的目的是什麼?
是為了讓開發人員和使用者知道伺服器是正常處理了請求還是出現了錯誤。瞭解目的,對於我們去了解狀態碼為什麼會這樣分,是非常必要的事情,至少心裡不那麼感覺到陌生了。
而在狀態碼中,有一個系列非常重要,那就是 3XX
系列。
301
,302
的區別
302 臨時重定向
臨時重定向,意識是當服務端關閉的時候,客戶端發起 url
請求,是不能成功的。它還需要向服務端發起請求,讓服務端重定向到目標網址,也就是返回 location
,然後再轉到目標網址。
PS: 思考一下,為什麼會有 302 ?
301 永久重定向
永久重定向,是即使服務端關閉了,瀏覽器端發起 url
請求,也可以不經過服務端而直接轉到目標網址。除非清理快取,否則以後再次訪問都是直接訪問另一個地址。
HTTP 請求方法
可以這樣理解,HTTP
就好比一個物件引數,裡面有 Method
,代表 HTTP
的請求方法,用來告訴伺服器,客戶端訪問你的 url
的目的是什麼,是獲取資訊,上傳資料還是刪除資訊。通常用到的最多就是 GET
和 POST
。經常用的 GET
和 POST
就不說了,這裡說一下 OPTIONS
:
OPTIONS
是為客戶端提供一種查詢 URL
地址中有哪些可用的訪問方式的方法。
PS: 留給思考,這個 OPTIONS
的使用場景是什麼呢?
POST
和 PUT
的區別:
POST
:POST
的資料,伺服器必須保證資料被完整的儲存,並且不允許出現重複的 POST
資料提交。通常在 HTML
中通過表單來提交資料。
PUT
: PUT
允許客戶端提交重複的資料,當提交重複的資料時,會用新提交的資料覆蓋掉伺服器已有的資料。
PS: 這裡推薦一本我讀過的書籍 《圖解HTTP》寫的很不錯,圖文並茂,簡單易懂,值得閱讀。
HTTP是怎麼在服務端走的
看下面我畫的一張圖,這是伺服器端程式、Web
伺服器、客戶端之間的關係:
上圖是主流的模式,Web
伺服器僅起到橋樑的作用,即將瀏覽器的 HTTP
請求解碼,轉換成伺服器端程式能夠識別的介面呼叫方式,然後伺服器端程式會將生成的返回封裝成 HTTP Response
,並返回給使用者。
注意1:
在服務端,使用者發的請求,如果是為了獲取靜態資源的話,一般是不經過伺服器端程式的,直接通過服務端的快取機制,返回資源給使用者,比如 Nginx
的靜態資源快取。不走服務端程式,會大大提高響應速度。
注意2:
服務端一般都是在公司的內網,外網是無法訪問的,發起 HTTP
請求,其實大多數情況下都是先通過 Nginx
進行反向代理,同時也是負責流量轉發,將不同的請求轉發給內網特定的伺服器。
Socket
Socket
在漢語中是指孔或插座的意識,顧名思義,插上了就可以通訊了。Socket
一開始是作為 BSD UNIX
的程式通訊機制,然後逐漸成為主流作業系統共同遵守的網路程式設計標準。
Socket
是什麼
Socket
是一個通訊鏈的控制程式碼,可以用來實現不同虛擬機器或不同計算機之間的通訊,也可以實現相同主機內的不同程式之間的通訊。
Socket
的組成
Socket
= IP
地址 + 埠 + 協議
IP 地址 + 埠 + 協議
組成一個唯一標識,用來標識一個通訊鏈路。
可以看到,Socket
其實是對 TCP/IP
進行了高度封裝,遮蔽了很多網路細節。這樣可以使開發者更好地進行網路程式設計。其實就是我們寫個高度封裝內部細節的函式,通過傳參來完成指定的行為。
可以這麼說,所有的 TCP/UDP
等程式設計,基本都是按照 Socket
協議標準來進行程式設計的,換句話說,Socket
是一套標準,就好比 DOM
,所有語言都可以按照 DOM
的介面標準來實現自己的邏輯。
Socket
有自己的原語,開發者可以按照 Socket
的原語在不同語言下的實現方式來進行網路程式設計。
談談 WebSocket
WebSocket 是什麼?
這是 HTML5
定義的一種新的標準協議,實現了瀏覽器與伺服器的全雙工通訊。我們可以將 WebSocket
理解為 Web + Socket
,它是一種雙工通訊。
什麼是雙工通訊?
就是在同一時刻,我既可以扮演通訊雙方的傳送方,也可以扮演通訊雙方的接收方。
為什麼會出現 WebSocket
在 WebSocket
出來之前,前端的 Web
通訊基本就靠 HTTP
,但是 HTTP
( 1 或者 2 ) 請求本身有一些缺陷,比如:
- 首部資訊冗餘,每次傳送請求,都要攜帶大量冗餘資訊。
- 不能實現雙工通訊。
所以在這個技術背景下,WebSocket
技術出現了,彌補了 HTTP
的缺陷。但是我們又不能不用 HTTP
,因為已經用的場景太多了,所以就綜合了一下,讓 WebSocket
協議是在 HTTP
協議之上的。這樣就可以做到平穩過渡到新的通訊協議上了。
WebSocket
的通訊原理
WebSocket
是建立在 HTTP
之上的,也就意味著你要建立 WebSocket
的話,需要走一次 HTTP
,走完後,你的 WebSocket
就建立起長連線了。然後只要不是主動斷開的,就會保持好客戶端和服務端之間的連線,不會使其斷開。當有資料傳輸的時候,會直接進行傳輸,不再發起 HTTP
請求。
前端使用 WebSocket
很簡單,就那麼幾個 API
,可自行去檢視。但是我們要清楚每個 API
究竟發生了什麼事情,只有理解了背後的那些真相,我們才算是真正理解了 WebSocket
。
WebSocket 優點
- 支援推送功能,服務端可以向客戶端推送資料。
- 減少通訊量,一方面是
WebSocket
的首部資訊很小,另一方面是不需要頻繁進行HTTP
連線了,可以進行持久連線。
這裡推薦一篇文章,寫的挺不錯,可以看看:
C/S 和 B/S 架構
對於前端工程師來說,還是要去了解一下 web
架構的發展演變的,提到發展演變,不得不說一下 C/S
和 B/S
架構。
C/S
C/S
,即 Client/Server
,當前網路程式設計的主流架構模型。 Clent
是客戶端的意識,S
是 服務端的意識。
B/S
即 Browser/Server
,是使用 Web
瀏覽器作為客戶端的應用軟體。
從上面介紹我們可以推斷出,C/S
中的 C
有很多,比如 APP
,桌面應用等。但是 B/S
中的 B
只特指瀏覽器。
問題來了,B/S
結構與 C/S
結構相比,有什麼區別或者說有什麼優勢呢?
B/S 的優缺點
優點
第一: 最顯而易見的就是,B/S
部署升級快,無需應用程式更新,因為 B/S
系統的所有應用程式都是部署在伺服器上的,不需要更新客戶端軟體。所以很多 APP
內都內嵌 H5
,Hybrid
。 因為不需要稽核,可以直接釋出。為什麼不需要稽核呢,是因為前端的跨域限制,JS
是無法獲取裝置其他資訊的,不需要擔心安全問題,也就不用稽核了。
第二: 跨平臺,因為作業系統都支援 Web
瀏覽器,所以只需要在瀏覽器中執行就好了。
缺點
安全性要求高,B/S
架構是建立在廣域網上的,面向所有使用者。通過 url
就可以訪問伺服器端資源,所以安全性要求要比 C/S
要高。
備註
- 沒有寫過多細節,一些細節自行去理解吧,也可以私聊我技術交流。
- 本文在整體上闡述了一個前端工程師應該要去掌握的網路知識。
- 本文字數還行,看著應該不怎麼累( 笑哭臉 )。
參考連線
文末總結
讀到這,我們會發現,網路知識沒有那麼神祕,認真去學習,你也可以搞定前端網路知識。
交流
掘金系列技術文章彙總如下,覺得不錯的話,點個 star 鼓勵一下,也可以 github
關注我一波,持續輸出精品文章。
我是原始碼終結者,歡迎技術交流,歡迎關注我的掘金部落格,不定期分享知識。
對了,還差了什麼,當然是祝各位小夥伴豬年大吉吧!!