簡介: 簡單來說,當使用者在浏覽器的位址欄中輸入 URL 并點選回車後,浏覽器從服務端擷取資源,然後将内容顯示在頁面上。這個過程經過了:浏覽器緩存 -> DNS 域名解析 -> URL 編碼 -> 使用 HTTP 或者使用 HTTPS 協定發送請求 -> - 對于通路靜态資源的 HTTP 請求:CDN -> CDN 回源到對象存儲 OSS 或者源伺服器 - 對于通路動态資源的 HTTP 請求:負載均衡器 Nginx -> 應用伺服器 -> 緩存系統 -> 存儲系統
當使用者在浏覽器的位址欄中輸入 URL 并點選回車後,頁面是如何呈現的。
簡單來說,當使用者在浏覽器的位址欄中輸入 URL 并點選回車後,浏覽器從服務端擷取資源,然後将内容顯示在頁面上。這個過程經過了:浏覽器緩存 -> DNS 域名解析 -> URL 編碼 -> 使用 HTTP 或者使用 HTTPS 協定發送請求 ->
- 對于通路靜态資源的 HTTP 請求:CDN -> CDN 回源到對象存儲 OSS 或者源伺服器
- 對于通路動态資源的 HTTP 請求:負載均衡器 Nginx -> 應用伺服器【API 網關(Zuul、GateWay 等)-> 内部服務(微服務,Controller、Service、DAO)】-> 緩存系統(Redis、EhCache 等) -> 存儲系統(MySQL、PostgreSQL、MongoDB 等)
為了減少響應時間,整個過程中的幾乎每一個環節都會有緩存。
為了提高系統的可用性、性能,整個過程中的很多環節都需要部署多節點。
浏覽器
當使用者在浏覽器的位址欄中輸入 URL 并點選回車後,首先由浏覽器進行處理。
浏覽器緩存
當使用者在浏覽器的位址欄中輸入 URL 并點選回車後,浏覽器會檢視自己是否緩存了該資源。
- 如果浏覽器緩存了該資源,并且緩存未過期,那麼直接從緩存中擷取資源,不向服務端發送請求(命中強緩存)。
- 如果浏覽器緩存了該資源,但是緩存已經過期了,那麼浏覽器向服務端發送條件請求。服務端會根據條件請求首部字段(If-Match、If-Modified-Since 等)來判斷是否命中協商緩存。
- 如果命中了協商緩存,那麼服務端會傳回 304 狀态碼(Not Modified),而不傳回浏覽器請求的資源。告訴浏覽器可以直接用浏覽器緩存中的資源。
- 如果沒有命中協商緩存,那麼伺服器傳回浏覽器請求的資源。
DNS 域名解析
當使用者在浏覽器的位址欄中輸入 URL 并點選回車後,浏覽器要判斷 URL 中的是 IP 位址,還是域名。如果 URL 中的是域名,那麼首先要做的就是域名解析。
域名解析的過程:首先是浏覽器檢視浏覽器的緩存。如果浏覽器中沒有該域名的緩存,那麼浏覽器詢問【本地 DNS 解析器】,【本地 DNS 解析器】首先檢視本地 DNS 緩存。如果本地 DNS 緩存中沒有該域名的緩存,那麼【本地 DNS 解析器】請求【本地 DNS 伺服器】進行域名解析。如果【本地 DNS 伺服器】中沒有該域名的緩存,那麼【本地 DNS 伺服器】向 DNS 系統中的其他遠端 DNS 伺服器發送查詢請求。
- 如果域名解析失敗,浏覽器會展示一個報錯頁面,提示域名不存在。
- 如果域名解析成功,浏覽器就擷取到一個域名對應的 IP 位址。
以【本地 DNS 解析器】請求【本地 DNS 伺服器】進行 www.CDNbook.com 域名的解析為例:
(1)【本地 DNS 解析器】向【本地 DNS 伺服器】發送域名解析請求。(8)【本地 DNS 解析器】收到來自【本地 DNS 伺服器】的應答。
(2)【本地 DNS 伺服器】向【根 DNS 伺服器】發送域名解析請求,【根 DNS 伺服器】傳回 .com 頂級域的域名伺服器清單(多條 NS 記錄)。
(4)【本地 DNS 伺服器】收到應答後,在 .com 頂級域的域名伺服器清單中選擇一個 IP 位址,向這個 IP 位址對應的 DNS 伺服器發送域名解析請求,.com 頂級域的域名伺服器傳回 CDNbook.com 域的域名伺服器清單。
(6)【本地 DNS 伺服器】收到應答後,在 CDNbook.com 域的域名伺服器清單中選擇一個 IP 位址,向這個 IP 位址對應的 DNS 伺服器發送域名解析請求,CDNbook.com 域的域名伺服器傳回 www.CDNbook.com 域的 A 記錄清單(多個 IP 位址)。
(8)【本地 DNS 伺服器】收到應答後,在 www.CDNbook.com 域的 A 記錄清單中選擇一個 IP 位址,将該 IP 位址傳回給【本地 DNS 解析器】。
(9)浏覽器擷取到域名對應的 IP 位址,這個 IP 位址可能是 CDN 伺服器的 IP 位址,也可能是源伺服器的 IP 位址。無論是什麼伺服器的 IP 位址,浏覽器都會向這個伺服器發送請求,伺服器将使用者請求的内容傳回給浏覽器。
URL 編碼
URL 編碼也被稱為百分号編碼。
URL 編碼的作用是:在 URL 中,使用 “安全的字元”(允許出現的字元、無歧義的字元) 替換 “不安全的字元”(不允許出現的字元、有歧義的字元)
- 将 “非 ASCII 字元” 編碼為 “ASCII 字元”,便于在 URL 中傳輸非 ASCII 字元。(URL 中隻能出現 ASCII 字元,不能出現非 ASCII 字元)
- 将 “空格” 編碼為 “%20”,便于在 URL 中傳輸空格。(URL 中不能出現空格)
- 将 “沒有表示特殊含義的保留字元” 進行 URL 編碼。(URL 中多個查詢參數之間用 & 符号分隔。如果參數值中包含了 & 字元,那麼會對 URL 解析造成影響,是以需要對造成歧義的 & 符号進行編碼)
URL 編碼的規則:簡單來說,如果需要對一個字元進行 URL 編碼,首先需要判斷該字元是否是 ASCII 字元:
- 如果一個字元是 ASCII 字元,那麼對該字元進行 URL 編碼,首先需要把該字元的 ASCII 的值表示為兩個 16 進制的數字,然後在其前面放置轉義字元 %,就得到了該字元的 URL 編碼結果。
- 如果一個字元是非 ASCII 字元,那麼對該字元進行 URL 編碼,首先需要使用指定的字元編碼方式(建議使用 UTF-8 字元編碼),将 “非 ASCII 字元” 編碼為位元組序列(位元組序列即二進制資料);然後對其位元組序列進行 URL 編碼。URL 編碼 “二進制資料”,首先需要把 “二進制資料” 表示為 8 位組的序列,将每個 8 位組表示為兩個 16 進制的數字,然後在其前面放置轉義字元 %,就得到了 “二進制資料” 的 URL 編碼結果。
HTTPS 通信
浏覽器使用 HTTP 或者使用 HTTPS 協定和伺服器通信。
使用 HTTPS 協定通信,通信的雙方會先建立 TCP 連接配接,然後執行 TLS 握手,之後就可以在安全的通信環境裡發送 HTTP 封包了。
一開始,用戶端和服務端都處于 close 狀态。
先是服務端監聽某個端口,此時服務端處于 listen 狀态。
這個時候用戶端就可以發送連接配接請求封包了。
第一次握手
用戶端會主動發送連接配接請求封包,随機初始化序列号為 x,并把 SYN 标志位設定為 1,表示 SYN 封包。
用戶端發送 SYN 封包後,用戶端進入 syn_sent 狀态。
第二次握手
服務端收到 SYN 封包後,服務端會發送 SYN-ACK 封包,用于對用戶端發送的 SYN 封包進行應答。
服務端會随機初始化序列号為 y,确認序列号設定為 x + 1,并把 SYN 标志位、ACK 标志位設定為 1。
服務端發送 SYN-ACK 封包後,服務端進入 syn_receive 狀态。
第三次握手
用戶端收到 SYN-ACK 封包後,用戶端會發送 ACK 封包,用于對服務端發送的封包進行應答。
用戶端會将序列号設定為 x + 1,确認序列号設定為 y + 1,ACK 标志位設定為 1。
用戶端發送 ACK 封包後,用戶端處于 established 狀态。
當服務端收到 ACK 封包後,服務端進入 established 狀态。
此時 TCP 連接配接就建立完成了,用戶端和服務端就可以互相發送資料了。
TLS 握手
TLS 握手過程的簡要描述:通信的雙方在 TLS 握手的過程中協商 TLS 的版本号、密碼套件,交換随機數、數字證書和密鑰參數,最終通信的雙方協商得到會話密鑰。("Hello" 消息交換随機數,"Key Exchange" 消息交換 "Pre Master Secret")
- 浏覽器給伺服器發送 "Client Hello" 消息,伺服器給浏覽器發送 "Server Hello" 消息。通信的雙方協商 TLS 的版本号、密碼套件,并交換随機數。
- 交換數字證書:伺服器為了向浏覽器證明自己的身份,伺服器給浏覽器發送 "server Certificate" 消息,以發送數字證書鍊,其中包含了兩個證書。一個是 CA 機構頒發的數字證書,另一個是 CA 機構的數字證書。
- 伺服器給浏覽器發送 "Server Key Exchange" 消息,浏覽器給伺服器發送 "Client Key Exchange" 消息。通信的雙方交換密鑰參數(Client Params 和 Server Params),然後通信的雙方就用 ECDHE 算法算出 "Pre Master Secret"。
- 通信的雙方根據自己已知的參數(Client Random、Server Random 和 Pre Master Secret)算出主密鑰 "Master Secret",并使用主密鑰拓展出更多的密鑰(會話密鑰),避免隻用一個密鑰帶來的安全隐患。
- 浏覽器給伺服器發送 "Change Cipher Spec" 消息,伺服器也給浏覽器發送 "Change Cipher Spec" 消息。告訴對方:後續傳輸的都是對稱密鑰加密的密文。
- 浏覽器給伺服器發送 "Finished" 消息,伺服器也給浏覽器發送 "Finished" 消息。通信的雙方把之前發送的資料做個摘要,再用對稱密鑰加密一下,讓對方做個驗證。
- 雙方都驗證成功,握手正式結束,之後就可以正常收發被加密的 HTTP 請求和響應了。
TCP / IP 模型的通信
發送資料包
當使用者在浏覽器的位址欄中輸入 URL 并點選回車後,首先由浏覽器進行處理,這些處理相當于應用層功能。浏覽器處理完成以後,浏覽器依據 HTTP 規範建構封包,并将 HTTP 封包發送給傳輸層的 TCP。
TCP 子產品的處理:TCP 根據浏覽器的訓示,負責建立連接配接、發送資料以及斷開連接配接。TCP 在浏覽器發送過來的資料前端再加上自己的 TCP 首部,随後将附加了 TCP 首部的包再發送給網絡層的 IP。
IP 子產品的處理:IP 将 TCP 傳過來的 TCP 首部和 TCP 資料合起來當做自己的資料,并在 TCP 首部的前端再加上自己的 IP 首部。IP 包生成後,參考路由控制表決定接受此 IP 包的路由器 或 主機。随後,IP 包将被發送給連接配接這些路由器 或 主機網絡接口的驅動程式,以實作真正的發送資料。
如果尚不知道接收端的實體位址(MAC 位址),可以利用 ARP(Address Resolution Protocol) 通過 IP 位址查找實體位址(MAC位址)。
隻要知道了對端的實體位址(MAC 位址),就可以将 MAC 位址和 IP 位址交給以太網的驅動程式,以實作真正的發送資料。
網絡接口(以太網驅動) 的處理:以太網的驅動程式将 IP 傳過來的 IP 首部和 IP 資料合起來當做自己的資料,并在 IP 首部的前端再加上自己的以太網首部。以太網資料包将通過實體層傳輸給接收端。
接收資料包
網絡接口(以太網驅動) 的處理:主機收到以太網包以後,首先從以太網的包首部找到實體位址(MAC 位址)。主機根據實體位址(MAC 位址),判斷是否為發給自己的包。
- 如果接收到的不是發給自己的包,那麼主機丢棄資料。
- 如果接收到的恰好是發給自己的包,那麼主機接收資料并查找以太網包首部中的類型域(類型域記錄上一層的協定類型),進而确定将資料傳給哪個處理程式。
- 如果上一層協定是 IP,那麼就将資料傳給處理 IP 的程式;
- 如果上一層協定是 ARP,那麼就将資料傳給處理 ARP 的程式;
- 如果以太網包首部的類型域包含了一個無法識别的協定類型,那麼主機丢棄資料。
IP 子產品的處理:IP 子產品收到 IP 包首部及後面的資料部分以後,也做和以太網驅動類似的處理。
- 如果判斷得出包首部中的 IP 位址與自己的 IP 位址比對,那麼就接收資料并查找 IP 包首部中的類型域(類型域記錄上一層的協定類型),進而确定将資料傳給哪個處理程式。
- 如果上一層協定是 TCP,那麼就将資料傳給處理 TCP 的程式;
- 如果上一層協定是 UDP,那麼就将資料傳給處理 UDP 的程式。
對于有路由器的情況下,接收端的 IP 位址往往不是自己的 IP 位址,此時需要借助路由控制表,在查找到應該送達的主機 或 路由器以後再轉發資料。
TCP 子產品的處理:TCP 子產品收到 TCP 包首部及後面的資料部分以後,首先會計算一下校驗和,判斷資料是否被破壞。然後檢查是否在按照序号接收資料。最後檢查端口号,進而确定将資料傳給哪個具體的應用程式。
TCP 子產品接收資料完畢後,接收端給發送端發送一個 “确認(ACK)”。如果發送端沒有收到這個确認資訊,那麼發送端會認為接收端沒有接收到資料,然後發送端會一直反複發送。
資料被完整地接收以後,會傳給由端口号識别的應用程式。
應用程式的處理:接收端應用程式會直接接收發送端發送的資料。伺服器準備好發送端應用程式所需的資料以後,以同樣的方式将資料發送到發送端應用程式。
服務端
當浏覽器的請求到達服務端之後,請求首先經過 Linux 虛拟伺服器 LVS,排程器将網絡請求分發到 Nginx 上。
- 如果 Nginx 上緩存的有使用者請求的内容,那麼 Nginx 直接将使用者請求的内容發送給浏覽器。
- 如果 Nginx 上沒有緩存使用者請求的内容,那麼 Nginx 通路應用伺服器(Web 伺服器,比如 Java 的 Tomcat / Netty / Jetty,Python 的 Django)擷取資源,再将使用者請求的内容傳回給浏覽器。Nginx 會根據緩存政策緩存從應用伺服器擷取到的資源,浏覽器也會根據緩存政策緩存收到的内容。
Nginx 也可以直接通路緩存系統嘗試擷取資源(Varnish 緩存靜态資源,Redis 緩存動态資源)。如果緩存系統中沒有使用者請求的内容,再通路應用伺服器擷取資源。
當 Nginx 的請求到達應用伺服器之後,請求首先經過 API 網關。API 網關根據路由規則,将外部通路網關位址的流量路由到内部服務叢集中正确的服務節點上。網關還可以根據需要作為流量過濾器來使用,提供某些額外的可選的功能,例如:
- 流量治理:流量控制、服務容錯(限流、降級、熔斷)
- 安全防護、通路控制:防刷控制、防爬蟲、黑白名單、認證、授權、資料完整性校驗、資料加密
- 監控:性能監控、日志監控
- 其他:協定适配轉換、緩存
外部通路網關位址的流量被路由到内部服務叢集中正确的服務節點上之後,服務節點會再通路緩存系統(比如 Redis、EhCache 等),存儲系統(比如 MySQL、PostgreSQL、MongoDB 等)實作業務操作,擷取資源。
服務節點将擷取到的資源傳回給 API 網關,API 網關将資源傳回給 Nginx,Nginx 再将使用者請求的内容傳回給用戶端,用戶端依據 HTTP 規則解析封包,并将使用者請求的内容顯示在頁面上。
文章來源:真正的飛魚_https://developer.aliyun.com/article/1174258?spm=a2c6h.12883283.index.54.4c554307l26Ijj