- Web全棧開發:從入門到實戰
- 董雪燕編著
- 4575字
- 2021-09-30 19:57:03
1.2 每一次瀏覽網頁都發生了什么
如今,人人都“掛”在網上,好像上網是一件再平常不過的事兒。只要我們在瀏覽器地址欄中輸入一個網址,便能輕松打開一個網頁,這看似極為簡單的幾秒鐘,背后卻默默發生了很多事情。要說清楚這背后的原理,我們需要先從網絡通信談起。
1.2.1 通信
眾所周知,上網必須要依靠網絡才能得以實現。無論你是用手機還是臺式機訪問網頁,都離不開網絡的支持。隨著數以千萬計的網絡設備入網,網絡這條高速公路變得異常繁忙。在這條高速路上行走的是各式各樣的網絡設備。包括手機、臺式機、筆記本、路由器等。
回想一下,當我們用手機與另一個朋友聯系時,雙方首先都要有一個電話號碼,這個號碼就像身份證號一樣是唯一的,這樣才能保證準確地聯系到的是朋友,而不是別人。同樣的道理,網絡中一臺計算機與另一臺計算機之間的通信,各自也有“號碼”,這個號碼稱作IP地址。為了保證通信不會出錯,這個IP地址必須是唯一的。
每當你打開一個網頁時,本質上來說,是你本地的計算機想要和網站運營商的服務器主機通信,目的是請求訪問網站相關的所有資源,即一個網頁,服務器主機收到請求后,便會立即去尋找,如果一切順利,它會把所有資源都發送到你所在的本地計算機,最后瀏覽器負責顯示該網頁。其中,本地的計算機是客戶端(Client),而運營商提供服務的主機是服務器(Server)。
為什么說服務器是一臺主機
一般來說,計算機是指一臺具有完整上網功能的臺式機或筆記本電腦,一般包括顯示設備、主機箱、鼠標和鍵盤等硬件。相對地,主機則只是包含主機箱內的所有核心硬件,而沒有像顯示器和鼠標等輸入、輸出設備。因為這些核心硬件就足以完成計算機的核心任務,比如資源的管理,文件和數據的傳輸和存儲等。
大型的網站運營商一般都有自己獨立的機房用于存放多臺服務器主機,或者租用專用的服務器,用于為鄰近的客戶端計算機提供服務。
每次打開一個網頁時,相當于是客戶端與服務器建立了一次通信。這里的通信可以簡單理解為一次兩者展開的會話,會話開始的標志是從打開瀏覽器輸入網址的那一刻,而結束則代表關閉網頁或退出瀏覽器。為了保證會話的順利,通信雙方要遵循統一的協議,即超文本傳輸協議(簡稱HTTP)。該協議規定了通信的雙方必須以請求-響應的方式展開,指定客戶端能發送什么類型的請求以及服務器端能給出什么響應,以及資源的格式等屬性,這些信息以HTTP報文的形式返回給客戶端的瀏覽器。
客戶端與服務器端之間的通信過程可以這樣理解,當客戶端發出對資源的請求時,服務器則負責查找是否存儲有請求的資源,如果有,則將與資源相關的所有信息發送給客戶端,即對請求做出響應。之后客戶端的瀏覽器會對資源進行緩存并加載,最終網頁的內容得以渲染在本地計算機的屏幕上。如果請求的資源不存在,則返回一些提示碼(404)和警告信息(資源不存在)。
我要的是網頁,為什么說是資源?
其實,瀏覽器中打開的每一個網頁,它的實質是一個HTML文檔,又稱HTML類型的資源,更進一步來看,該文檔通常還包含CSS樣式表、圖片、JavaScript腳本等文件,這些文件構成了網頁上對應類型的資源。因此,當提到瀏覽器通過地址欄中輸入網址請求資源,其本質是根據資源的URL(統一資源定位符)尋找文件,URL用于表示其在本地計算機緩存中(一般是內存)的物理地址或網絡服務器主機上的網絡地址。
總結一下,一個網頁包含多種不同類型的資源,每一個資源都有一個唯一的標識符,瀏覽器是通過URL請求資源,而服務器則根據URL尋找資源。可見,資源可以是一個HTML文檔,也可以是一張圖片。
接下來,我們來看看每次通信的過程中發生了什么?
1.2.2 統一資源定位器
在計算機中,所有文件都是依靠目錄的方式組織起來的,比如一幅圖片的存儲路徑為D:/web/1.jpg,依靠這個路徑,我們就可以很方便地找到該圖片。類似地,網絡中的所有資源也是依靠同樣的方式,只不過它有一個很酷的名字——URL(統一資源定位),它主要用來尋找服務器上存儲的資源。那么瀏覽器中的地址和URL的關系到底是什么呢?這一節我們就來一探究竟。
我們以一個網址http://tech.sina.com.cn/csj/2020-02-11/doc-iimxyqvz1887699.shtml為例,來看看該URL是如何標識一個HTML文檔資源的。這個地址可以分解成3塊來看:
(1)協議類型(http),這是客戶端計算機和服務器主機進行網絡通信的基礎,雙方必須遵守同一個協議才能保證正常通信,否則就是“雞同鴨講”,完全不在一個頻道。
(2)服務器主機的IP地址和端口號(“tech.sina.com.cn”),這是為了從眾多的主機群中找到目標服務器主機,建立一對一的通信。所以,這一串字符對應的是一個服務器主機的域名,它等價于一串IP地址(58.49.227.129)。也就是說,我們既可以通過IP地址也可以通過域名來訪問服務器主機。而端口號則是特定的網頁程序與外界通信的出口,采用HTTP協議的Web應用通常采用是默認的端口號:80或8080。
端口號一定要有嗎?
答案是肯定的。為了回答這個問題,我們從IP地址與端口的關系來說一說。當兩臺計算機在通信時,IP地址可以幫助我們定位到目標主機,但是由于目標主機上一般運行著多個網絡程序,因此,還需要端口號來標識每一個不同的上網程序(進程)。準確來說,要尋找一個特定的網絡程序,必須依靠IP地址和端口號的組合。其中,端口號是聯網程序(進程)與外界進行通信(比如數據交換)的必經之地。如果做一個比喻的話,IP地址和端口號的關系可以近似為樓棟和樓門號的關系。
回到新浪網的例子,好像網址中并未出現端口號,那是因為在默認情況下,HTTP協議的程序都采用80,這個可以省略。如果有其他非80的端口號,則必須要在地址欄中明確給出。
(3)文件路徑(“csj/2020-02-11/doc-iimxyqvz1887699.shtml”),這一串看似復雜,其實逐一分解就會發現其實很簡單。首先,從最后doc-iimxyqvz1887699.shtml看,這是一個shtml文檔資源,“.”前面的字符串是文件名;接著,“2020-02-11”是該文件存儲的文件目錄(即一個文件夾);然后,“csj”是上上一級文件目錄。它跟在域名之后,表示對于網站站點的根目錄的相對路徑,說明目標網頁文檔的存儲位置是相對于根目錄下的csj/2020-02-11文件夾中。
這就更清楚了,上述地址中的URL對應的是新浪網上一篇文章的網頁,它背后的本質是該地址指向存放在新浪的某一臺服務器主機上的一個HTML文檔。
shtml和html文檔是一回事?
其實,一個HTML文檔的后綴名有三個,分別是htm、shtml和html。也就是說,看見網頁對應的URL的末尾是以它們結尾的話,都代表是對一個HTML文檔資源的請求。
其中htm和html完全是一個意思,可以互換。但是為了技術上更容易理解,推薦使用html。
shtml和html對于本地瀏覽器來說都是HTML格式的靜態網頁。但有一點不同的是,shtml中多了一些包含SSI技術命令和服務器端指令的語句,這些語句很大的可能是說這些HTML的內容是由服務器端的腳本動態生成的。更多關于靜態和動態網頁的介紹后面會有更詳細地解釋,這里不再贅述。
1.2.3 瀏覽器如何理解網頁
前面提到,客戶端的瀏覽器會接收到服務器主機發來的HTTP報文,這些報文信息經過傳輸和解析后就隱藏在瀏覽器中。
當你在百度搜索框輸入“新浪”(即客戶端發送一個HTTP請求到百度服務器),按下F12打開開發者測試工具,找到Network選項,可以看到甘特圖下方有一個表格,如圖1.2所示。它包含著無數行數據,其實每一行數據都代表著對不同資源的描述。

圖1.2
具體來看,每一行中包含一些列屬性,這些屬性是對資源的描述,屬性的具體含義說明如表1.1所示。
表1.1 請求資源的屬性說明

續上表

通過表1-1中描述的信息,我們可以知道與網頁中包含的所有資源的相關信息,從而有利于做進一步的網頁優化。
接著,在Name列,隨意選擇一個資源單擊打開,如圖1.3所示的Headers。這里隱藏著更重要的信息,即請求頭和數據、響應頭和數據。

圖1.3
一般來說,一次正常通信的報文頭(Headers)包括四部分內容:General、Response Headers、Request Headers和Query String Parameters(可選項)。
(1)General(通用信息)
它是本次請求-響應通信的基本信息,包括請求的新浪網頁(Request URL),請求方式是GET,HTTP狀態碼是200,表示正常,以及遠程地址。
(2)Response Headers(響應頭部)
這一部分是服務器發出響應的一些重要信息,其中主要的信息字段如表1.2所示。
表1.2

(3)Request Headers(請求頭部)
這一部分是關于客戶端發出請求相關的一些重要信息,具體包括以下內容:
·Accept:表示能夠接受的網頁形式,包括text(文本)、JavaScript代碼等;
·Cookie:用來存儲一些用戶信息以便讓服務器辨別用戶的身份(大多數需要登錄的網站上面會比較常見),比如Cookie會存儲一些用戶的用戶名和密碼,當用戶登錄后就會在客戶端產生一個Cookie來存儲相關信息,這樣瀏覽器通過讀取Cookie的信息去服務器上驗證,通過后會判定你是合法用戶,從而允許查看相應網頁;
·Host:發送請求時,這是必須指定的主機和端口號,主機是www.baidu.com,端口號80省略即可;
·Referer:這個一般都會有,告訴服務器我是從哪個頁面鏈接過來的,服務器借此獲得一些信息。比如從我主頁上鏈接到一個朋友那里,他的服務器就能夠從HTTP Referer中統計出每天有多少用戶點擊我主頁上的鏈接訪問朋友的網站;
·User-Agent:告訴HTTP服務器,客戶端使用的操作系統和瀏覽器的名稱和版本,嘗試找找有沒有Chrome以及其版本號。我們上網登錄論壇的時候,往往會看到一些歡迎信息,其中列出了你的操作系統的名稱和版本,你所使用的瀏覽器的名稱和版本,這往往會讓很多人感到很神奇,實際上,服務器應用程序就是從User-Agent這個請求報頭域中獲取到這些信息的;
·X-Requested-With:這個屬性用于在服務器端判斷前端的請求(Request)是來自Ajax異步請求,還是傳統的同步請求。當它為XMLHttpRequest時,表明是異步請求;如果為null,則表明為傳統的請求。
(4)Query String Parameters(查詢字符參數)
從圖1.4可知,由于用戶輸入了關鍵字“新浪”,所以它就是我們查詢的關鍵字參數。這里的參數為加了s的復數,表明允許你一次輸入多個查詢參數,這些參數和值可以用“&”符號連接,比如wd=`新浪`&author=`小紅`。

圖1.4
基于以上這些隱藏在瀏覽器中的信息,客戶端和服務器的通信才會變得真正可行。
1.2.4 從程序方面理解網頁
這一節要從程序的角度來理解一下要想成功打開并顯示一個網頁,都需要依靠哪些程序來完成。這里還是以在百度主頁https://www.baidu.com中搜索“新浪”過程為例,來看看前端采用JavaScript程序和后端采用PHP程序的網頁訪問和加載過程,客戶端與服務器之間的通信見圖1.5。

圖1.5
圖1.5可以分成三個階段來解讀。
(1)客戶端發送請求
在同一時段,網絡中通常有多臺本地主機在瀏覽器中輸入百度的網址,這些請求會首先經過DNS域名解析服務器,負責將提取出來的服務器名稱轉換成一個IP地址,比如:220.181.38.148,從而去網絡中查找該地址對應的百度上的一臺服務器主機。
(2)服務器返回響應
服務器主機上一定裝有一款Web服務器程序(比如Apache),它通過遵守HTTP(超文本傳輸協議)與客戶端瀏覽器進行信息交流,并負責存放目標資源的相關文件。一旦用戶在百度的搜索框內輸入“新浪”,服務器很快便去搜索與關鍵詞新浪相關的HTML文檔、CSS樣式表、圖片以及JavaScript程序。由于搜索的部分結果可能是從數據庫中動態查詢到的,所以在JavaScript程序中,還會通過服務器端的PHP腳本程序,該程序一般放在PHP應用服務器上,主要實現對數據庫的查詢,而數據庫一般是以一個數據庫管理系統程序的形式出現。
在通信正常且請求成功的情況下,新浪相關的查詢結果會返回給PHP程序,接著它又把結果告訴JavaScript程序。
(3)瀏覽器解析代碼并渲染網頁內容
JavaScript程序會在瀏覽器中解析和執行,隨著搜索結果的相關資源下載到本地緩存中,網頁中相關的CSS樣式和JavaScript程序也會異步加載,最終會成功渲染(即網頁內容是以畫圖的方式顯示在屏幕上)到網頁中,即搜索結果頁面展現在操作者面前。
在網頁內容的加載過程中,文字和CSS樣式會首先顯示在頁面上,圖片和視頻等消耗更多網絡資源的加載時間比較長,這就是為什么當網絡環境不好時,你可能只看到一些文字,圖片卻沒有正常顯示或顯示不全。