Files
build-web-application-with-…/zh-tw/03.1.md
2019-02-26 01:40:54 +08:00

161 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 3.1 Web工作方式
我們平時瀏覽網頁的時候,會開啟瀏覽器,輸入網址後按下回車鍵,然後就會顯示出你想要瀏覽的內容。在這個看似簡單的使用者行為背後,到底隱藏了些什麼呢?
對於普通的上網過程系統其實是這樣做的瀏覽器本身是一個客戶端當你輸入URL的時候首先瀏覽器會去請求DNS伺服器透過DNS取得相應的域名對應的IP然後透過IP地址找到IP對應的伺服器後要求建立TCP連線等瀏覽器傳送完HTTP Request請求套件後伺服器接收到請求套件之後才開始處理請求套件伺服器呼叫自身服務返回HTTP Response響應套件客戶端收到來自伺服器的響應後開始渲染這個Response套件裡的主體body等收到全部的內容隨後斷開與該伺服器之間的TCP連線。
![](images/3.1.web2.png?raw=true)
圖3.1 使用者訪問一個Web站點的過程
一個Web伺服器也被稱為HTTP伺服器它透過HTTP協議與客戶端通訊。這個客戶端通常指的是Web瀏覽器(其實手機端客戶端內部也是瀏覽器實現的)。
Web伺服器的工作原理可以簡單地歸納為
- 客戶機透過TCP/IP協議建立到伺服器的TCP連線
- 客戶端向伺服器傳送HTTP協議請求套件請求伺服器裡的資源文件
- 伺服器向客戶機發送HTTP協議應答套件如果請求的資源包含有動態語言的內容那麼伺服器會呼叫動態語言的解釋引擎負責處理“動態內容”並將處理得到的資料返回給客戶端
- 客戶機與伺服器斷開。由客戶端解釋HTML文件在客戶端螢幕上渲染圖形結果
一個簡單的HTTP事務就是這樣實現的看起來很複雜原理其實是挺簡單的。需要注意的是客戶機與伺服器之間的通訊是非持久連線的也就是當伺服器傳送了應答後就與客戶機斷開連線等待下一次請求。
## URL和DNS解析
我們瀏覽網頁都是透過URL訪問的那麼URL到底是怎麼樣的呢
URL(Uniform Resource Locator)是“統一資源定位符”的英文縮寫,用於描述一個網路上的資源, 基本格式如下
scheme://host[:port#]/path/.../[?query-string][#anchor]
scheme 指定底層使用的協議(例如http, https, ftp)
host HTTP伺服器的IP地址或者域名
port# HTTP伺服器的預設埠是80這種情況下埠號可以省略。如果使用了別的埠必須指明例如 http://www.cnblogs.com:8080/
path 訪問資源的路徑
query-string 傳送給http伺服器的資料
anchor 錨
DNS(Domain Name System)是“域名系統”的英文縮寫是一種組織成域層次結構的計算機和網路服務命名系統它用於TCP/IP網路它從事將主機名或域名轉換為實際IP地址的工作。DNS就是這樣的一位“翻譯官”它的基本工作原理可用下圖來表示。
![](images/3.1.dns_hierachy.png?raw=true)
圖3.2 DNS工作原理
更詳細的DNS解析的過程如下這個過程有助於我們理解DNS的工作模式
1. 在瀏覽器中輸入www.qq.com域名作業系統會先檢查自己本地的hosts檔案是否有這個網址對映關係如果有就先呼叫這個IP地址對映完成域名解析。
2. 如果hosts裡沒有這個域名的對映則查詢本地DNS解析器快取是否有這個網址對映關係如果有直接返回完成域名解析。
3. 如果hosts與本地DNS解析器快取都沒有相應的網址對映關係首先會找TCP/IP引數中設定的首選DNS伺服器在此我們叫它本地DNS伺服器此伺服器收到查詢時如果要查詢的域名包含在本地配置區域資源中則返回解析結果給客戶機完成域名解析此解析具有權威性。
4. 如果要查詢的域名不由本地DNS伺服器區域解析但該伺服器已快取了此網址對映關係則呼叫這個IP地址對映完成域名解析此解析不具有權威性。
5. 如果本地DNS伺服器本地區域檔案與快取解析都失效則根據本地DNS伺服器的設定是否設定轉發器進行查詢如果未用轉發模式本地DNS就把請求發至 “根DNS伺服器”“根DNS伺服器”收到請求後會判斷這個域名(.com)是誰來授權管理並會返回一個負責該頂級域名伺服器的一個IP。本地DNS伺服器收到IP資訊後將會聯絡負責.com域的這臺伺服器。這臺負責.com域的伺服器收到請求後如果自己無法解析它就會找一個管理.com域的下一級DNS伺服器地址(qq.com)給本地DNS伺服器。當本地DNS伺服器收到這個地址後就會找qq.com域伺服器重複上面的動作進行查詢直至找到www.qq.com主機。
6. 如果用的是轉發模式此DNS伺服器就會把請求轉發至上一級DNS伺服器由上一級伺服器進行解析上一級伺服器如果不能解析或找根DNS或把轉請求轉至上上級以此迴圈。不管本地DNS伺服器用的是轉發還是根提示最後都是把結果返回給本地DNS伺服器由此DNS伺服器再返回給客戶機。
![](images/3.1.dns_inquery.png?raw=true)
圖3.3 DNS解析的整個流程
> 所謂 `遞迴查詢過程` 就是 “查詢的遞交者” 更替, 而 `迭代查詢過程` 則是 “查詢的遞交者”不變。
>
> 舉個例子來說,你想知道某個一起上法律課的女孩的電話,並且你偷偷拍了她的照片,回到寢室告訴一個很仗義的哥們兒,這個哥們兒二話沒說,拍著胸脯告訴你,甭急,我替你查(此處完成了一次遞迴查詢,即,問詢者的角色更替)。然後他拿著照片問了學院大四學長學長告訴他這姑娘是xx系的然後這哥們兒馬不停蹄又問了xx系的辦公室主任助理同學助理同學說是xx系yy班的然後很仗義的哥們兒去xx系yy班的班長那裡取到了該女孩兒電話。(此處完成若干次迭代查詢,即,問詢者角色不變,但反覆更替問詢物件)最後,他把號碼交到了你手裡。完成整個查詢過程。
透過上面的步驟我們最後取得的是IP地址也就是瀏覽器最後發起請求的時候是基於IP來和伺服器做資訊互動的。
## HTTP協議詳解
HTTP協議是Web工作的核心所以要了解清楚Web的工作方式就需要詳細的瞭解清楚HTTP是怎麼樣工作的。
HTTP是一種讓Web伺服器與瀏覽器(客戶端)透過Internet傳送與接收資料的協議,它建立在TCP協議之上一般採用TCP的80埠。它是一個請求、響應協議--客戶端發出一個請求伺服器響應這個請求。在HTTP中客戶端總是透過建立一個連線與傳送一個HTTP請求來發起一個事務。伺服器不能主動去與客戶端聯絡也不能給客戶端發出一個回呼(Callback)連線。客戶端與伺服器端都可以提前中斷一個連線。例如當瀏覽器下載一個檔案時你可以透過點選“停止”鍵來中斷檔案的下載關閉與伺服器的HTTP連線。
HTTP協議是無狀態的同一個客戶端的這次請求和上次請求是沒有對應關係的對HTTP伺服器來說它並不知道這兩個請求是否來自同一個客戶端。為了解決這個問題 Web程式引入了Cookie機制來維護連線的可持續狀態。
>HTTP協議是建立在TCP協議之上的因此TCP攻擊一樣會影響HTTP的通訊例如比較常見的一些攻擊SYN Flood是當前最流行的DoS拒絕服務攻擊與DdoS分散式拒絕服務攻擊的方式之一這是一種利用TCP協議缺陷傳送大量偽造的TCP連線請求從而使得被攻擊方資源耗盡CPU滿負荷或記憶體不足的攻擊方式。
### HTTP請求套件瀏覽器資訊
我們先來看看Request套件的結構, Request套件分為3部分第一部分叫Request line請求行, 第二部分叫Request header請求頭,第三部分是body主體。header和body之間有個空行請求套件的例子所示:
GET /domains/example/ HTTP/1.1 //請求行: 請求方法 請求URI HTTP協議/協議版本
Hostwww.iana.org //伺服器端的主機名
User-AgentMozilla/5.0 (Windows NT 6.1) AppleWebKit/537.4 (KHTML, like Gecko) Chrome/22.0.1229.94 Safari/537.4 //瀏覽器資訊
Accepttext/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 //客戶端能接收的MIME
Accept-Encodinggzip,deflate,sdch //是否支援流壓縮
Accept-CharsetUTF-8,*;q=0.5 //客戶端字元編碼集
//空行,用於分割請求頭和訊息體
//訊息體,請求資源引數,例如POST傳遞的引數
HTTP協議定義了很多與伺服器互動的請求方法最基本的有4種分別是GET,POST,PUT,DELETE。一個URL地址用於描述一個網路上的資源而HTTP中的GET, POST, PUT, DELETE就對應著對這個資源的查刪4個操作。我們最常見的就是GET和POST了。GET一般用於取得/查詢資源資訊而POST一般用於更新資源資訊。
透過fiddler抓套件可以看到如下請求資訊:
![](images/3.1.http.png?raw=true)
圖3.4 fiddler抓取的GET資訊
![](images/3.1.httpPOST.png?raw=true)
圖3.5 fiddler抓取的POST資訊
我們看看GET和POST的區別:
1. 我們可以看到GET請求訊息體為空POST請求帶有訊息體。
2. GET提交的資料會放在URL之後`?`分割URL和傳輸資料引數之間以`&`相連,如`EditPosts.aspx?name=test1&id=123456`。POST方法是把提交的資料放在HTTP套件的body中。
3. GET提交的資料大小有限制因為瀏覽器對URL的長度有限制而POST方法提交的資料沒有限制。
4. GET方式提交資料會帶來安全問題比如一個登入頁面透過GET方式提交資料時使用者名稱和密碼將出現在URL上如果頁面可以被快取或者其他人可以訪問這臺機器就可以從歷史記錄獲得該使用者的賬號和密碼。
### HTTP響應套件伺服器資訊
我們再來看看HTTP的response套件他的結構如下
HTTP/1.1 200 OK //狀態行
Server: nginx/1.0.8 //伺服器使用的WEB軟體名及版本
Date:Date: Tue, 30 Oct 2012 04:14:25 GMT //傳送時間
Content-Type: text/html //伺服器傳送資訊的型別
Transfer-Encoding: chunked //表示傳送HTTP套件是分段發的
Connection: keep-alive //保持連線狀態
Content-Length: 90 //主體內容長度
//空行 用來分割訊息頭和主體
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"... //訊息體
Response套件中的第一行叫做狀態行由HTTP協議版本號 狀態碼, 狀態訊息 三部分組成。
狀態碼用來告訴HTTP客戶端,HTTP伺服器是否產生了預期的Response。HTTP/1.1協議中定義了5類別狀態碼 狀態碼由三位數字組成,第一個數字定義了響應的類別
- 1XX 提示資訊 - 表示請求已被成功接收,繼續處理
- 2XX 成功 - 表示請求已被成功接收,理解,接受
- 3XX 重新導向 - 要完成請求必須進行更進一步的處理
- 4XX 客戶端錯誤 - 請求有語法錯誤或請求無法實現
- 5XX 伺服器端錯誤 - 伺服器未能實現合法的請求
我們看下面這個圖展示了詳細的返回資訊左邊可以看到有很多的資源返回碼200是常用的表示正常資訊302表示跳轉。response header裡面展示了詳細的資訊。
![](images/3.1.response.png?raw=true)
圖3.6 訪問一次網站的全部請求資訊
### HTTP協議是無狀態的和Connection: keep-alive的區別
無狀態是指協議對於事務處理沒有記憶能力,伺服器不知道客戶端是什麼狀態。從另一方面講,開啟一個伺服器上的網頁和你之前開啟這個伺服器上的網頁之間沒有任何聯絡。
HTTP是一個無狀態的連線導向的協議無狀態不代表HTTP不能保持TCP連線更不能代表HTTP使用的是UDP協議面對無連線
從HTTP/1.1起預設都開啟了Keep-Alive保持連線特性簡單地說當一個網頁開啟完成後客戶端和伺服器之間用於傳輸HTTP資料的TCP連線不會關閉如果客戶端再次訪問這個伺服器上的網頁會繼續使用這一條已經建立的TCP連線。
Keep-Alive不會永久保持連線它有一個保持時間可以在不同伺服器軟體如Apache中設定這個時間。
## 請求例項
![](images/3.1.web.png?raw=true)
圖3.7 一次請求的request和response
上面這張圖我們可以瞭解到整個的通訊過程同時細心的讀者是否注意到了一點一個URL請求但是左邊欄裡面為什麼會有那麼多的資源請求(這些都是靜態檔案go對於靜態檔案有專門的處理方式)。
這個就是瀏覽器的一個功能第一次請求url伺服器端返回的是html頁面然後瀏覽器開始渲染HTML當解析到HTML DOM裡面的圖片連線css指令碼和js指令碼的連結瀏覽器就會自動發起一個請求靜態資源的HTTP請求取得相對應的靜態資源然後瀏覽器就會渲染出來最終將所有資源整合、渲染完整展現在我們面前的螢幕上。
>網頁優化方面有一項措施是減少HTTP請求次數就是把儘量多的css和js資源合併在一起目的是儘量減少網頁請求靜態資源的次數提高網頁載入速度同時減緩伺服器的壓力。
## links
* [目錄](<preface.md>)
* 上一節: [Web基礎](<03.0.md>)
* 下一節: [Go建立一個Web伺服器](<03.2.md>)