通過瀏覽器訪問一個 PHP 檔案時發生了什麼?

Gtaker發表於2018-09-05

瀏覽器解析 URL

一個標準的 URL 語法通常都建立在由 9 部分構成的通用格式上,瀏覽器會從使用者輸入的 URL 字串中解析對應的內容:

<schema>://<user>:<password>@<host>:<port>;<params>?<query>#<frag>
複製程式碼

其中比較重要的有:

  • schema——協議版本
  • host——主機地址
  • port——埠號
  • path——檔案路徑
  • query——即 query_string 查詢字串

DNS 域名解析

如果上面提到的 host 部分為域名,則需要通過 DNS 對其進行解析。

查詢本地 host 檔案

使用者可以在本地的 host 檔案中指定域名和 IP 地址的對應關係,所以瀏覽器會先去本地的 host 檔案中尋找是否存在對應的 IP 地址,如果存在,則向該地址傳送請求。

DNS 解析

  • 查詢本地域名伺服器
  • 本地域名伺服器將查詢報文轉發到域名伺服器並進行查詢
  • 域名伺服器根據具體的域名地址,向本地域名伺服器返回頂級域名伺服器地址
  • 本地域名伺服器向頂級域名伺服器傳送查詢請求
  • 頂級域名伺服器向本地域名伺服器返回許可權域名伺服器地址
  • 本地域名伺服器向許可權域名伺服器傳送查詢請求

最終,我們通過 DNS 解析獲得了主機的 IP 地址

建立 TCP 連線

三次握手

三次握手的過程是老生常談了,資料比較多,這裡就不具體贅述了,只列出大致過程:

  1. 客戶端傳送 SYN 報文,請求建立連線
  2. 服務端傳送 ACK 報文和 SYN 報文,表示同意客戶端的建立連線請求,同時自己也請求建立連線
  3. 客戶端傳送 ACK 報文,表示請求已收到

使用 APR 協議定位目標地址

在乙太網中,一臺主機要把資料幀傳送到同一區域網上的另一臺主機時,裝置驅動程式必須知道乙太網地址才能傳送資料。而我們只知道IP地址,這時就需要採用 ARP 協議將 IP 地址對映為乙太網地址。 在傳送第一個 SYN 報文時,IP 層會通過 ARP 協議查詢出目標主機的 MAC 地址。 (TCP/IP協議——ARP詳解

第一次握手時傳送的第一個 SYN 報文首先會通過 connect() 函式到達 IP 層,之後 IP 層會通過查詢路由表獲取目標主機的 MAC 地址並將其快取,然後該 MAC 地址會被通過 send() 函式交給網路介面進行封裝,最終將資料傳送出去。
PS:引用資料的文章非常詳細的解釋了不同情況下該過程的工作細節,建議認真閱讀一遍。

建立 SSL 隧道

如果請求使用的是 HTTPS 協議,則在建立 TCP 連線後,需要通過四次握手在其之上再建立一條加密隧道,即 SSL

四次握手

  1. 客戶端:
    • 傳送協議版本號
    • 傳送支援的加密方法
    • 生成隨機數 1client random)並傳輸給服務端
  2. 服務端:
    • 選擇併傳送要使用的加密方法
    • 傳送數字證照
    • 生成隨機數 2server random)並傳輸給客戶端
  3. 客戶端:
    • 驗證數字證照
    • 生成一個隨機數 3premaster secret),使用公鑰對其進行加密後傳輸給服務端
    • 使用 client randomserver randompremaster secret 生成 會話金鑰session key
  4. 伺服器:
    • 使用私鑰對加密字串進行解密,獲得 premaster secret
    • 使用 client randomserver randompremaster secret 生成 會話金鑰session key

四次握手通過非對稱加密的方式使客戶端和服務端獲得並持有相同的 session key,並通過該 key 值對之後的會話過程進行對稱加密

傳送 HTTP(s)請求

瀏覽器使用前兩步獲得的資訊構造請求報文,並通過第三步建立起來的 TCP 連線向服務端傳送 HTTP 請求。 其中,請求報文的基本格式為:

<method><request-URL><version>  
<headers>  
<entity-body>
複製程式碼

這三部分分別為起始行首部主體,通過瀏覽器請求發起的預設為 GET 請求,所以沒有主體部分。
下面展示了一個假想的 HTTP 報文,其中第一行為起始行,二三行為首部

GET /index.html HTTP/1.1
Accept: text/html
Host: www.foo.com
複製程式碼

服務端代理處理請求

服務端代理即為 nginxapache 等伺服器軟體,它們會根據配置檔案將請求對映為伺服器上具體的檔案,並根據檔案型別對其進行處理返回。

直接返回靜態檔案(.html)

如果檔案是型別為 .html.txt.xml 的靜態檔案,則只需將其內容作為響應的 entity-body 直接返回給客戶端。

解析動態檔案(.php)

如果檔案型別為 .php.jsp.asp 等動態檔案,則需要對其進行解析。這裡我們只講解對 .php 檔案的操作,以 nginx 伺服器為例。

  • nginx 得知要處理的為 .php 檔案
  • nginx 呼叫自己的 Fast-CGI 模組,構造 Fast-CGI 請求
  • nginx 向 PHP-FPM 傳送 Fast-CGI 請求,此時 nginx 相當於一個反向代理伺服器
  • PHP-FPM 的 master 程式收到請求
  • master 將請求分配給特定的 worker 程式
  • worker 程式使用內嵌的 PHP-CGI 直譯器對 PHP 檔案進行解析,返回結果並生成對 nginx 的響應
  • nginx 獲得來自 PHP-FPM 的響應,即得到靜態檔案

服務端代理響應請求

nginx 生成響應報文,返回給客戶端。響應報文和請求報文只有起始行的語法有所不同:

<version><status><reason-phrase>
<headers>
<entity-body>
複製程式碼

關閉 TCP 連線

老生常談喜聞樂見的四次揮手環節,因為相關資料實在是太多了,這裡也不具體贅述了,只列出大致過程:

  1. 客戶端傳送 FIN 報文,表示自己的所有資料已傳輸完畢
  2. 服務端返回 ACK 報文,表示請求已收到
  3. 服務端傳送 FIN 報文,表示自己的所有資料也都已經傳輸完畢
  4. 服務端返回 ACK 報文,表示請求已收到,並進入 TIME_WAIT 狀態

客戶端對返回的檔案進行解析

瀏覽器會解析返回的 HTML / CSS / JS 等檔案,並最終將頁面展現在使用者面前。

相關文章