從輸入URL到頁面可交互的過程探究之一:從服務端到客戶端

原文鏈接:https://segmentfault.com/a/1190000020076547#articleHeader0

最近發現國外有一個系列,專門探究從輸入URL到頁面可交互的詳細過程,是一份乾貨十足的好資料。筆者決定分爲四篇文章對其進行有刪減地翻譯,只希望能對大家有所幫助,畢竟這是前端必備的知識點,也是容易忽略掉某些細節的知識點。事先聲明,這個系列完全由筆者手翻,如有翻譯不當的地方,懇請讀者給出改進意見!

接下來開始第一篇——從服務端到客戶端

在瀏覽器執行任何工作之前,它需要先知道訪問的是哪裏。有幾種方法可以實現訪問:在地址欄中輸入URL、點擊(或觸碰)一個頁面上或其他app中的超鏈接、或者點擊你的收藏。無論是哪種情況,都會觸發一個動作——導航。導航永遠是網頁中交互的第一步,因爲它觸發瞭如下一系列事件的連鎖反應直至網頁被加載。

初始化請求

一旦URL被提供給瀏覽器去加載,以下這些事情就會悄悄在背後發生:

檢查HSTS

首先,瀏覽器需要判斷這個URL是否明確爲HTTP(不安全)協議。如果它是一個HTTP的請求,那麼瀏覽器則需要檢查這個域名是否在HSTS的清單中(HTTP Strict Transport Security——嚴格安全傳輸)。這個清單包含了一個預加載好的名單以及你之前訪問過的使用HSTS的網站名單,它們都是存放在瀏覽器中的。如果你請求的HTTP開頭的host處於在HSTS清單中,那這個請求會被強制轉爲HTTPS開頭的URL而非HTTP。這就是爲什麼你會發現當你試圖在一個現代瀏覽器中輸入http://www.bing.com 會被轉爲https://www.bing.com

檢查SERVICE WORKERS

接着,瀏覽器需要判斷service worker是否可以用來處理請求——這對於那些離線的沒有網絡連接的用戶來說至關重要。Service workers相對來講是比較新的瀏覽器特性。它通過對網絡請求的攔截來提供離線應用的能力,這些請求都可以被保留在腳本控制的緩存中。這是很有用的,因爲它使網站能夠更好地控制何時使用緩存的項目。這些緩存是跟域名綁定的,這意味着每個域都可以有自己的緩存黑盒,並與其他域的緩存隔離開。

當一個頁面被訪問時,可以註冊一個Service worker,這個動作是由一個工作線程來完成的,它可以把service worker的註冊和URL映射記錄在本地數據庫中。要判斷一個service worker是否被安裝,只需在這個本地數據中查找是否有對應的URL。如果爲service worker查到了對應的URL,它就會被允許處理請求的迴應。而如果瀏覽器支持Navigation Preload的新特性,且開發者使用了它,那麼瀏覽器會同時去發起首次導航請求。這是有好處的,因爲它避免了瀏覽器因爲service worker啓動過慢而對頁面渲染的影響。

當瀏覽器發現沒有service worker來處理初始化請求時,就會繼續網絡請求層。

檢查網絡緩存

瀏覽器會通過網絡請求層檢查緩存中是否存在全新的響應。這經常是由響應頭中的Cache-Control字段決定的,字段中設置的max-age值可以決定緩存多久會刷新,而no-store字段可以表明是否應該被緩存。可想而知,如果瀏覽器在緩存中找不到任何東西,那麼就需要進行網絡請求了。而如果在緩存中有一個全新的響應,它就會被立即返回以用於頁面加載。如果存在一個不夠“新”的資源,那麼瀏覽器會把這個請求轉爲一個附帶條件的校驗請求,也就是請求頭帶上If-Modified-Since或者If-None-Match去告訴服務端當前瀏覽器存的是哪個版本的緩存。服務端則可以返回HTTP 304狀態碼(沒有更改)告訴瀏覽器這個緩存是最新的,不帶響應正文;或者返回HTTP 200狀態碼告訴瀏覽器這個緩存資源已經過期了,並直接返回最新的資源

檢查網絡連接

如果現在有一個和主機、端口建立起連接的請求,那麼它會被瀏覽器複用而不是重新去建立一個,否則,瀏覽器會走網絡層以瞭解是否需要執行DNS(域名系統)查詢。這個動作的具體流程是,先尋找本地的DNS緩存(存儲在你的設備上),然後根據DNS緩存是否過期來決定是否訪問遠程域名服務器(它們由互聯網服務提供商ISP分配主機地址),域名服務器最終會返回準確的IP地址給瀏覽器進行連接。

某些情況下,瀏覽器能夠預先知道哪些域名會被訪問,從而先準備好對這些域名的連接。一個網頁可以通過在link標籤中使用資源提示(resource hints),比如rel="preconnect" 來提示瀏覽器提前準備好連接。在如下場景中,資源提示是很有用的,比如一個用戶在必應的搜索結果頁,而通常的預期中,前幾條搜索結果是最有可能被用戶訪問的。此時,提前準備好對那些域名的連接可以在那些網頁被點擊之後節省掉DNS查詢和域名連接的消耗。

建立起連接

瀏覽器現在可以與服務器建立起連接了,且服務端知道自己需要從客戶端接收和發送消息了。如果我們是使用TLS,我們需要執行一次TLS握手流程以驗證服務器提供的證書。

發送請求給服務器

第一個通過這個連接發起的請求叫做頂級頁面請求。通常情況,這個請求的資源會是一個HTLML文件,從服務器返回到客戶端

處理響應

當響應以數據流的形式到達客戶端後,客戶端就開始進行解析了。首先,瀏覽器會檢查響應頭。HTTP頭部是以鍵值對的形式作爲HTTP響應的一部分。如果響應頭指示要進行重定向(比如,通過Location字段),瀏覽器就會再一次進行導航並回到最初的那一步,檢查是否需要執行HSTS的升級(爲HTTPS)。

如果服務器的響應數據被壓縮或分塊了,瀏覽器會嘗試對它進行解壓和合並。

待響應被解讀完成後,瀏覽器還會並行地將其寫入網絡緩存中。

接着,瀏覽器會搞清發送過來的文件的MIME類型,這樣它才能以適當的方式去加載這份文件。比如,一份圖片文件會原封不動地被加載進來,但HTML文件則會被執行解析和渲染。如果HTML解析器被調用了,那麼它會掃描出那些可能要下載的資源文件的URL,以便瀏覽器在頁面渲染之前就可以開始去下載。這一部分的更多細節會在系列文章的下一篇中具體展開。

截至目前,被請求的導航URL已經輸入到了瀏覽器的歷史中,這樣它就可以被用於瀏覽器導航的前進和後退功能了。

這裏有一張更詳細的流程圖,它可以讓你對目前討論的內容有個總體的概覽:

如你所知的,頁面會繼續發起請求,因爲頁面上還有很多對整體體驗很重要的子資源,比如圖片,腳本,和樣式表。另外,這些子資源中引用到的其他資源,比如背景圖片(CSS中引用的),或者其他由fetch()import()AJAX請求發起的資源。如果沒有這些的話,我們將只能看到一個原始的無交互的空頁面。

再談緩存

剛剛已經提到,瀏覽器會管理網絡緩存,以便在多種場景下能對下載好的資源的重複利用。這對那些長久不更新的資源尤其有用,比如logo和第三方的腳本文件。我們應該儘可能地利用好這些緩存,因爲這有利於減少對外的網絡請求數,取而代之的是本地的可複用的緩存資源。

響應頭中的Cache-Control字段控制着瀏覽器的緩存邏輯。某些情況下,你可以謹慎地告訴瀏覽器完全不要進行緩存,比如使用Cache-Control: no-store,因爲這個資源在預期中是一直在變化的。另一種情況下,當給定URL的響應內容永遠不會變化時,我們可以設置Cache-Control: immutable以便瀏覽器可以永遠地緩存它。實際應用中,當我們使用不同的URL來指向不同版本的同一份資源時,我們就可以採用這種做法,而非對同一個URL的資源進行更改,因爲被緩存的版本會一直被使用且不會去發送請求。

Origin模型

Origin是由協議,主機名和端口共同組成的。例如,https://www.bing.com:443 這個origin是由https的協議, www.bing.com 的主機名和443的端口組成的。只要其中任何一個部分有差異,那麼在兩者進行比較時,都會被認爲是不同源的。比如https://images.bing.com:443 和 http://www.bing.com:80 就是不同源的。

Origin對於瀏覽器來說是很重要的概念,因爲它定義了數據是如何被隔離和保護的。大多數情況,爲了安全考慮,瀏覽器會強制使用同源策略,意味着一個源無法訪問另一個源的數據。就像上面提到的兩個源——https://images.bing.com:443 和 http://www.bing.com:80 ,它們互相都無法訪問對方的緩存(service worker的)。

如果bing.com想要從microsoft.com加載一個Javascript文件,它就需要在實行同源策略的瀏覽中發起一個跨域資源請求。想要允許這種操作的話,microsoft.com就需要與bing.com通過指定CORS(跨域資源共享)的頭部進行合作。

總結

既然你已經明白了資源如何從服務器走到客戶端以及之間的所有細節,那麼請繼續關注網頁加載的下一步:從HTML標籤轉爲DOM。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章