揭秘現代網站流程:從輸入URL到頁面呈現的全過程

當你在瀏覽器中輸入一個 URL 並按下 Enter 鍵,背後會發生一系列複雜且有趣的技術過程,本文將深入探討了從輸入URL到頁面呈現的完整流程。

Last Updated:

前言

本篇的誕生是源自於希望透過寫作重新梳理自己對於網路流程的認識,加上想要讓自己的基礎更紮實一點。因此如果內容有誤或是想要討論的,歡迎來信與我討論!

正文

當你在瀏覽器中輸入 URL 並按下 Enter,這個簡單動作實際上觸發了一系列複雜的技術過程,最終讓網頁呈現在你眼前。今天,我們將深入解析這個過程中的每個步驟及其背後的技術細節。

1. 輸入URL

第一步,就是在瀏覽器的搜尋框中輸入一個 URL,例如:https://blog.hack.tw/,並按下 Enter。

2. 瀏覽器快取 (Browser Cache)

首先,瀏覽器會檢查本地快取(HTTP 快取和瀏覽器快取)以查詢是否有請求資源的副本。如果有,瀏覽器將直接從快取中載入資源,這樣可以避免發送HTTP請求,節省時間和資源。

瀏覽器快取的工作原理

瀏覽器快取指的是說瀏覽器將之前載入過的資源(例如HTML、CSS、JavaScript、圖片等)存在本地端,以便在下一次訪問相同資源時可以直接從本地讀取,就不需要重新從伺服器下載。這個過程能夠顯著提高網頁載入速度,減少流量消耗。

快取策略

瀏覽器會根據 HTTP Header中的快取控制指令來決定是否使用快取資源。例如,Cache-Control Header 可以包含 max-age ,指定資源可以在多長時間內被視為最新(fresh)的。當快取資源過期時,瀏覽器會發送一個條件請求 Conditional Requests(例如If-Modified-Since Header),詢問伺服器資源是否已經更新。如果資源沒有改變,伺服器會 return 一個304 Not Modified,告訴瀏覽器可以繼續使用快取資源。

快取的優點和挑戰

使用快取的主要優點包括加快網頁載入速度、減少網路流量消耗和降低伺服器負載。然而,快取本身也可能會有一些問題,例如要確保資源更新時快取能夠及時失效,否則使用者看到的就會是原本的快取頁面,以及處理不同使用者可能會看到不一致的內容。

DNS 解析

如果快取中沒有找到資源,那瀏覽器就要去該網站取的資源,而第一個步驟就是瀏覽器對該網站的 Domain 進行 DNS 解析(Parsing)。這個過程包括以下幾個步驟:

sequenceDiagram
  actor Browser
  participant LocalCache
  participant OS
  participant DNSServer
  participant Regional DNS Server
  participant RootServer
  participant TLDServer
  participant SLDServer
  Browser->>LocalCache: 檢查本地 DNS 快取
  LocalCache-->>Browser: 找到 IP Address
  Browser->>OS: 向作業系統請求解析
  OS->>DNSServer: 請求 DNS 解析
  DNSServer->>Regional DNS Server: 查詢區域 DNS Server
  Regional DNS Server-->>Browser: 找到 IP Address
  Regional DNS Server->>RootServer: 查詢根網域伺服器
  RootServer->>TLDServer: 查詢頂級網域伺服器
  TLDServer->>SLDServer: 查詢次級網域伺服器
  SLDServer-->>Browser: 返回 IP Address
  
  1. 瀏覽器檢查本地的 DNS 快取,如果找到相應的 IP Address 就可以直接使用。而本地快取是指瀏覽器和作業系統保存的最近查詢過的網域及其對應的IP Address,這樣可以加快後續的查詢速度。
  2. 如果沒有找到,瀏覽器會向作業系統請求 DNS 解析。像是我們可以透過寫入 /etc/hosts 來告訴瀏覽器指向的位置,有打過 Lab 像是 Hackthebox 的人可能很熟悉。
  3. 作業系統接收到請求後,會檢查其內部的 DNS 快取。如果沒有找到,作業系統會向設定的 DNS 伺服器(通常是路由器或 ISP 的 DNS 伺服器)發出請求。在這裡,區域 DNS 伺服器(Regional DNS Server)扮演著很重要的角色。區域 DNS 伺服器通常由 ISP 或特定地區的 ISP 運營,它們能夠快速回傳常見的 IP Address,因為它們快取了來自更高級別 DNS 伺服器的結果,特別是針對當地熱門網站,這樣可以降低查詢延遲。如果區域 DNS 伺服器也無法解析,它會向 ISP 或更高層的公共 DNS 伺服器(如 Cloudflare 的 1.1.1.1 或 Google 的 8.8.8.8)發送請求。
  4. DNS 伺服器會依次查詢根(root)網域伺服器、頂級網域伺服器和次級網域伺服器,直到找到對應的 IP Address(例如:104.16.132.229)。而這個步驟又牽涉到 DNS 解析的另一個過程,它會從根(Root)網域伺服器開始解析,這些伺服器負責指引查詢請求到相應的頂級網域伺服器(如.com、.org或.tw等)。再到頂級網域伺服器 TLD,這些伺服器負責指引查詢請求到負責特定網域的次級網域伺服器。最後是次級網域伺服器 SLD,然後返回具體網域的 IP Address。

DNS 解析中的優化技術

為了提高DNS解析的效率,現代瀏覽器和作業系統會使用多種優化技術,如:

  1. 並行查詢 Parallel Query: 同時向多個 DNS 伺服器發送查詢請求,以減少等待時間。
  2. DNS 預取 DNS Prefetch: 預先查詢可能會用到的網域,這樣使用者在點擊連結時可以更快地載入網頁。
  3. 分佈式快取 Distributed Caching: 將 DNS 查詢結果快取在多個位置,以提高查詢速度和可靠性。

使用 CDN

在 DNS 解析過程中,解析結果可能指向一個 CDN(內容分發網絡) 節點的IP Address。CDN 會根據地理位置將請求重定向到最近的節點,用來減少延遲並提高載入速度。

CDN 的工作原理

CDN 是一個由分佈在不同地理位置的伺服器組成的網絡,將內容快速傳遞給使用者。CDN 的主要目的是減少延遲,提升使用者體驗。它通過將內容快取在多個節點上,當使用者請求內容時,可以從最近的節點取得,而不是從原始伺服器遠程下載,同時可以提升可靠性,即使其中一個節點掛掉了,還是可以從其他節點拿到資源。

CDN 的優勢

  1. 降低延遲:通過將內容快取在接近使用者的伺服器上,CDN 能夠明顯的降低延遲,提升網頁載入速度。
  2. 減少伺服器負載:CDN 節點分擔了原始伺服器的負載,減少伺服器的壓力,提高系統的穩定性和可擴展性。
  3. 提升可用性:由於內容分佈在多個節點,即使某個節點出現故障,使用者仍然可以從其他節點取得內容,提升系統的可靠性。

CDN 的實現

CDN 實現的核心是將內容快取在多個伺服器上,這些伺服器根據地理位置分佈在不同的地區。當使用者請求內容時,CDN會自動選擇最接近使用者的節點進行回應。這個過程涉及多個技術環節,像是:

  1. 內容同步:將原始伺服器上的內容同步到 CDN 節點,確保所有節點上的內容一致。
  2. 請求重定向:通過 DNS 或其他技術,將使用者的請求重定向到最接近的 CDN 節點。
  3. 快取管理:根據內容的更新頻率和使用者的訪問模式,動態調整快取策略,確保使用者能夠取得最新的內容。

建立 TCP 連線

在拿到伺服器的 IP 後,用戶端與伺服器之間就會通過 TCP/IP 協議進行通信。也就是常常聽到的三次握手過程:

  1. 用戶端發送SYN(同步)Packet 到伺服器,請求建立連線。
  2. 伺服器收到後,回應一個SYN-ACK(同步-確認)Packet 表示接受請求。
  3. 用戶端再次回應一個 ACK(確認)Packet ,完成三次握手,成功建立連線。
sequenceDiagram
    participant Client
    participant Server

    Client->>Server: SYN
    Server-->>Client: SYN-ACK
    Client->>Server: ACK
  

TCP 三次握手的詳細過程

TCP(Transmission Control Protocol,傳輸控制協定)是網路通訊的核心協定之一,負責確保資料在用戶端和伺服器之間可靠傳輸。TCP三次握手是建立可靠連線的基本步驟,包括以下過程:

  1. SYN Packet:用戶端向伺服器發送一個SYN(同步序列號)Packet,這個 Packet 包含了一個初始序列號,用於標識後續通信的數據 Packet 順序。
  2. SYN-ACK Packet:伺服器收到SYN Packet後,回應一個SYN-ACK Packet,這個 Packet 包含伺服器的初始序列號(Initial Sequence Number, ISN),以及確認用戶端的 SYN Packet的序列號。
  3. ACK Packet:用戶端收到SYN-ACK Packet 後,回應一個ACK(確認)Packet,這個 Packet 確認伺服器的SYN-ACK Packet的序列號。然後,雙方的連線就建立完成了。

三次握手的重要性

TCP 三次握手的目的是確保雙方都能夠準備好進行數據傳輸,並協調 Packet 的順序。這個過程能夠有效避免 Data Packet 丟失和重複,確保通信的可靠性和穩定性。

TLS 握手(使用 HTTPS)

如果使用 HTTPS,則需要進行 TLS 握手以建立安全的加密連線:

  1. 用戶端發送 ClientHello 消息,包含支持的加密演算法和其他相關信息。
  2. 伺服器回應 ServerHello 消息,選擇加密演算法並發送伺服器憑證。
  3. 用戶端驗證伺服器憑證,並產生對稱加密密鑰,使用伺服器的公鑰加密後發送給伺服器。
  4. 伺服器使用私鑰解密,取得對稱加密密鑰,然後雙方使用該密鑰進行加密通信。

TLS 握手的詳細過程

TLS(Transport Layer Security,傳輸層安全性協定)是網路上保護數據安全的主要協定之一。TLS 握手過程牽涉很多步驟,用來確保通信的安全性,這邊我認為佛心企業 Cloudflare 的解釋足夠好了,小弟就不獻醜,直接引用 (來源: https://www.cloudflare.com/zh-tw/learning/ssl/what-happens-in-a-tls-handshake/),流程圖是用 Mermaid 畫的:

sequenceDiagram
    participant Client
    participant Server

    Client->>Server: ClientHello
    Server-->>Client: ServerHello
    Server-->>Client: Server Certificate
    Server-->>Client: ServerHelloDone
    Client->>Server: Client Key Exchange
    Client->>Server: Change Cipher Spec
    Server-->>Client: Change Cipher Spec
    Client->>Server: Finished
    Server-->>Client: Finished
  
  1. 用戶端問候(client hello)」消息: 用戶端通過向伺服器發送「問候」消息來開始握手。該消息將包含用戶端支援的 TLS 版本,支援的密碼套件,以及稱為一串稱為「用戶端亂數(client random)」的隨機位元組。

  2. 「伺服器問候(server hello)」消息: 作為對 client hello 消息的回復,伺服器發送一條消息,內含伺服器的 SSL 憑證、伺服器選擇的密碼套件,以及「伺服器亂數(server random)」,即由伺服器生成的另一串隨機位元組。

  3. 身份驗證: 用戶端使用頒發該憑證的憑證授權驗證伺服器的 SSL 憑證。此舉確認伺服器是其聲稱的身份,且客戶端正在與該域的實際所有者進行交互。

  4. 預主密鑰: 用戶端再發送一串隨機位元組,即「預主密鑰(premaster secret)」。預主密鑰是使用公開金鑰加密的,只能使用伺服器的私密金鑰解密。(用戶端從伺服器的 SSL 憑證中獲得公開金鑰。)

  5. 私密金鑰被使用:伺服器對預主密鑰進行解密。

  6. 生成工作階段金鑰:用戶端和伺服器均使用用戶端亂數、伺服器亂數和預主密鑰生成工作階段金鑰。雙方應得到相同的結果。

  7. 用戶端就緒:用戶端發送一條「已完成」消息,該消息用工作階段金鑰加密。

  8. 伺服器就緒:伺服器發送一條「已完成」消息,該消息用工作階段金鑰加密。

  9. 實現安全對稱加密:已完成握手,並使用工作階段金鑰繼續進行通信。

所有 TLS 交握都使用非對稱加密(公開金鑰和私密金鑰),但並不是所有的 TLS 交握都會在產生工作階段金鑰的過程中使用私密金鑰。

TLS 握手的安全性

TLS 握手的核心是通過公鑰加密技術確保密鑰交換的安全性,並通過數位憑證驗證伺服器的身份。這個過程能夠有效防止中間人攻擊,確保數據在傳輸過程中的機密性和完整性。

發送 HTTP 請求

建立安全的 TLS 連線後,用戶端就會開始發送 HTTP Request(例如:GET /p/browser-to-response-explain/ HTTP/1.1)到伺服器。

HTTP 請求的結構

HTTP 請求是使用者向伺服器請求資源的 Message,主要包含以下部分:

  1. Request Line:包括 HTTP 方法(如 GETPOST)、請求的 URL Path 和 HTTP 版本。
  2. Request Header:包含請求的 Metadata,如HostUser-AgentAcceptCache-Control等。
  3. Request Body通常僅在POST、PUT等方法中存在,用於傳遞資料。例如使用者想要登入某網站時,將 Username 和 Password 傳遞給網站,以證明自己的身份。

常見的HTTP Method

  1. GET:請求取得資源。
  2. POST:向伺服器提交數據。
  3. PUT:上傳指定資源。
  4. DELETE:刪除指定資源。
  5. HEAD:跟GET很像,但基本上只能收到 Status line 和 Header。
  6. OPTIONS: 詢問可以使用的 HTTP Method。

這邊僅列出比較常聽到的,詳細可參考 RFC 7231 section-4.3,另外HTTP Method 也可以自訂

下面是一個範例的 Request

1
2
3
4
5
6
7
GET /p/browser-to-response-explain/ HTTP/1.1
Host: blog.hack.tw
Accept-Language: zh-TW
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.6478.127 Safari/537.36
Connection: keep-alive
    
    

伺服器回應 Server Response

伺服器接收到 HTTP 請求後,處理並返回 HTTP 回應,包含狀態碼(如 1xx 資訊性訊息、2xx 成功、3xx 重定向、4xx 使用者端錯誤、5xx 伺服器錯誤)和所請求的資源(例如HTML文檔)。詳細可參考 RFC 7231 section-6,或是 Wikipedia

HTTP 回應的結構

HTTP回應是伺服器對用戶端請求的回應,包含以下主要部分:

  1. Status Line:包括 HTTP 版本、狀態碼和狀態描述。
  2. Response Header:包含回應的 meta-data,如 Date、Content-Type、Server等。
  3. Response Body:包含所請求的資源(如HTML文檔、圖片等)。

常見的 HTTP Status Code

  1. 1xx(資訊性狀態碼):表示請求已經被接受,正在處理中。
  2. 2xx(成功狀態碼):表示請求已成功處理(如200 OK)。
  3. 3xx(重定向狀態碼):表示需要進一步操作才能完成請求(如301 Moved Permanently)。
  4. 4xx(用戶端錯誤狀態碼):表示請求有錯誤,無法處理(如404 Not Found)。 或是418這種迷因
  5. 5xx(伺服器錯誤狀態碼):表示伺服器在處理請求時發生錯誤(如500 Internal Server Error)。
可以上http.cat查看各種Status Code貓,推薦看418

以下是 Response 的範例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
HTTP/2 418 I'm a teapot
Date: Wed, 28 Aug 2024 12:43:32 GMT
Content-Type: text/html; charset=utf-8
Vary: Accept-Encoding
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
X-Xss-Protection: 1; mode=block
Server: cloudflare

<!DOCTYPE html>
...
...
</html>

瀏覽器處理回應(Response)

瀏覽器接收到伺服器的回應後,開始解析 HTML 。瀏覽器引擎指揮各個部分的工作,將 HTML 交給渲染引擎。

瀏覽器的工作流程

瀏覽器的主要任務是將伺服器返回的 HTML 轉換為可視的網頁,這個過程包括多個步驟:

  1. 解析 HTML:瀏覽器解析 HTML 標籤(tag),產生對應的 DOM 節點(Node),並按照HTML結構組織成DOM Tree。
  2. 解析 CSS:瀏覽器解析 CSS 樣式,產生對應的 CSS 規則,並按照選擇器應用到相應的 DOM 節點,組織成 CSSOM。
  3. 構建渲染樹(Render tree):參考 DOM 和 CSSOM ,並且將目標瀏覽器需要的畫面元素建構成渲染樹(Render tree),這棵樹描述了網頁的結構和樣式。
    會說是參考是因為像是 display: none這種元素(Element)不會被瀏覽器渲染,也就是這個元素會完全從渲染樹消失,渲染時也不會佔據空間。 詳細可參考 https://developer.mozilla.org/en-US/docs/Web/CSS/display#none

原文如下:

none

Turns off the display of an element so that it has no effect on layout (the document is rendered as though the element did not exist). All descendant elements also have their display turned off. To have an element take up the space that it would normally take, but without actually rendering anything, use the visibility property instead.

  1. 佈局 Layout:根據渲染樹中的節點關係和樣式屬性,計算每個節點的確切位置和大小。
  2. 繪製 Paint:根據佈局計算的結果,將每個節點繪製到螢幕上,包括 Text、圖片、邊框等。

JavaScript 執行

在解析和佈局過程中,如果遇到 JavaScript,瀏覽器會將其交給 JavaScript 引擎執行。JavaScript 引擎會解析和執行腳本,可能會改變 DOM 和 CSSOM,導致佈局和繪製的重新計算。

JavaScript 的執行過程

  1. 解析:JavaScript 引擎將程式碼解析為語法樹。
  2. 編譯:將語法樹(Syntax Tree)轉換為機器碼,準備執行。
  3. 執行:執行機器碼,操作 DOM 和 CSSOM,

可能觸發佈局和繪製的重新計算。

TCP 四次揮手(連線終止)

當用戶端或伺服器一方希望終止連線時,會發送 FIN(終止)Packet。另一方收到 FIN Packet 後,回應 ACK Packet,確認收到終止請求。接著,接收 FIN Packet 的一方也發送一個 FIN Packet,請求終止連線。最初發送FIN Packet 的一方回應一個 ACK Packet,最終確認連線已終止,完成四次揮手。

TCP四次揮手的過程

  1. FIN Packet:發起終止的一方(例如用戶端)發送一個 FIN Packet,請求終止連線。
  2. ACK Packet:接收 FIN Packet的一方(例如伺服器)回應一個 ACK Packet,確認收到終止請求。
  3. FIN Packet:接收方(例如伺服器)再發送一個 FIN Packet,請求終止連線。
  4. ACK Packet:最初發送 FIN Packet的一方(例如用戶端)回應一個 ACK Packet,確認終止請求,連線正式終止。
sequenceDiagram
    participant Client
    participant Server

    Client->>Server: FIN
    Server-->>Client: ACK
    Server-->>Client: FIN
    Client->>Server: ACK
  

這個四次揮手的過程確保雙方都能夠有序地關閉連線,避免數據丟失和混亂。


最後的想法

以上是從輸入 URL 到網頁顯示的完整過程,涵蓋了每個技術步驟的基本解釋和一些背景。希望這篇文章能夠幫助你深入理解網頁載入背後的技術原理,這一過程看似簡單,實際上涉及了大量複雜的技術。理解這些過程不僅能增進我們對 Web 技術的認識,對於想研究 Web Security 的人也一定有所幫助。如果你有更多問題或需要進一步了解,歡迎來信討論!

Licensed under CC BY-NC-SA 4.0
Last updated on Sep 12, 2024