目錄
初識TCP/IP
了解HTTP之前我們得了解一下TCP/IP協議族。我們通常所說得TCP/IP協議族是互聯網相關的各類協議族的總稱,而HTTP屬於它內部的一個子集。還有一種說法認為TCP/IP是指TCP和IP這兩種協議。
TCP/IP協議族里重要的一點就是分層。從上到下依次分為以下4層:應用層、傳輸層、網絡層和數據鏈路層。
TCP/IP協議族4層模型
應用層
應用層的任務是通過應用進程間的交互來完成特定的網絡應用。TPC/IP協議族內預存了各類通用的應用服務。比如,FTP(文本傳輸協議)和DNS(域名系統)。HTTP協議也位於該層。
傳輸層
傳輸層主要為兩台計算機進程之前的通信提供數據傳輸服務,也就是傳輸應用層的報文。該層的協議有:TCP協議和UDP協議。
網絡層
網絡層用來處理網絡上流動的數據包。數據包是網絡傳輸的最小數據單。該層規定通過怎樣的路徑到達對方的計算機,並把數據包傳送給對方。在計算機網絡中進行通信,之間可能會經過很多網絡設備或者計算機,網絡層就是要選擇合適的傳輸路線。網絡層會把上一層的報文封裝成數據包。該層使用的是IP協議。
鏈路層
用來處理連接網絡的硬件部分。包括操作系統、硬件設備的驅動、網卡和光纖等物理設備。硬件上的范疇均在鏈路層的作用范圍之內。
發送端在層與層之間傳輸數據時,沒經過一層必須要加上該層的首部信息。反之,接收端在層與層傳輸時必須把首部去掉。這種把數據信息包裝起來的做法叫做封裝。
下面會講一講和HTTP密不可分的三個協議:IP、TCP、DNS
負責傳輸的IP協議
IP協議的作用就是把各類數據包傳送給對方。為了確保傳送的准確,則需要滿足各類條件。其中兩個重要的條件就是IP地址和MAC地址。IP地址指明了節點被分配到的地址,MAC地址是指網卡所屬的固定地址。IP地址是可變換的,而MAC地址基本上不會改變。
網絡通信的雙方在同一局域網的情況很少,通常需要多台網絡設備的中轉才能連接到對方。在中轉時,會利用下一站中轉設備的MAC地址來搜索下一個中轉目標。這時,會采用ARP協議,ARP是一種解析地址的協議,根據通信方的IP地址就可以反查出對應的MAC地址。在這個中轉的過程中,那些計算機、路由器等網絡設備只能獲悉很粗略的傳輸路線,這種機制稱為路由選擇。
確保可靠性的TCP協議
TCP位於傳輸層,提供可靠的字節流服務。所謂字節流服務,就是為了方便傳輸,TCP會將大數據分割成以報文段為單位的數據包進行管理。而可靠性涉及到的東西就很多了,比如三次握手、超時重傳、流量控制等等。這一塊會放到TCP/UDP的總結博客里面講,暫時只需要知道TCP建立連接會經過三次握手,斷開連接會經過四次揮手。
負責域名解析的DNS服務
DNS和HTTP一樣位於應用層。它提供域名到IP地址之間的解析服務。所謂域名就是類似於www.baidu.com這種字符串。為了方便記憶,計算機也可以被賦予域名。這樣我們就可以直接通過域名訪問,而不是毫無字面意義的IP地址。但是要讓計算機去理解域名,就有些困難了。為了解決這個問題,就需要用到DNS服務了。DNS提供域名查IP和IP查域名的服務。
在瀏覽器上輸入一個域名會發生什么?
最后,我們以一個常見的面試題,來總結一下在使用HTTP協議進行通信的過程中,IP協議、TCP協議和DNS服務發揮了哪些作用。
URI和URL
URL就是我們使用瀏覽器訪問WEB網頁時輸入的網頁地址,比如:https://www.baidu.com/。URL的全稱是統一資源定位符。
而URI是統一資源標識符。URI用字符串標識某一互聯網資源,而URL標識資源的地點,所以URL是URI的子集。為了讓你更直觀的認識URI,可以了解以下URI的格式:
登錄信息為指定用戶名和密碼,作為訪問服務器資源的登錄信息,此項是可選項。服務器地址就是域名,也可以是IP。端口號也是可選項,不填的就會使用默認端口號。文件路徑就是服務器上該資源的路徑。查詢字符串就是傳入到服務器的參數。片段標識符也是可選項,它通常可以標記出已獲取資源中的某個位置。
初識HTTP
請求和響應
HTTP協議的作用是用於客戶端和服務器端之間的通信。通過請求和響應的交互達成通信。HTTP協議規定,請求從客戶端發出,最后服務端響應請求並返回。
下面來看看請求報文的構成
方法就是請求的類型,URI上一節講過。協議版本就是HTTP的版本號,其他的部分待會再說。下面再看看響應報文的構成
狀態碼能反應該次請求的結果如何,圖中的200就代表請求成功。
HTTP是一種無狀態的協議,即HTTP協議本身不對請求和響應之間的通信狀態進行保存。雖然其本身不能保存,但是為了實現保持狀態的功能,於是引入了Cookie技術。關於Cookie后面再說。
接下來詳細說說前面提到的請求類型,也就是方法的意義。下面介紹以下HTTP/1.1中可使用的部分方法。
GET:獲取資源
GET方法用來請求訪問被URI識別的資源,如果請求的是文本圖片這些資源,那就保持原樣返回。如果請求的是接口,那么就返回程序執行的返回結果。
POST:傳輸數據
雖然我們也可以利用GET方法的參數來傳輸資源,但是一般還是用POST方法。雖然它們功能很相似,但是最主要的一個區別就是:GET方法的參數會顯示在URI上,也就是以?號開頭的。而POST方法的參數會放在主體里面。這樣對於傳輸數據來說,顯然會安全一點。
PUT:傳輸文件
要求在請求報文的主體中包含文件內容,然后保存到URI指定的位置。
HEAD:獲得報文首部
HEAD方法和GET方法一樣,只是不返回報文主體部分。用於確認URI的有效性以及資源更新的日期時間等。
DELETE:刪除文件
與PUT方法相反,DELETE請求刪除URI指定的資源。但是和PUT一樣,它們都不帶驗證機制,所以一般的話也不會使用PUT或者DELETE,都可以用POST替代,然后配合程序代碼來驗證刪除。
OPTIONS:查詢支持的方法
用以查詢URI指定資源支持的方法。
接着再說說前面提到的Cookie
Cookie
Cookie可以解決HTTP無狀態的問題。Cookie會根據從服務端返回的響應報文中的一個叫Set-Cookie的首部字段信息,來通知客戶端保存Cookie。當下次客戶端再次請求該服務端時就會在請求報文中加入Cookie值。常見的場景就是登錄。首先客戶端發送登錄請求,登錄成功后服務端返回用戶信息,然后客戶端把用戶信息存入Cookie,這樣用戶的登錄狀態就保持住了。當然,一般不會直接把用戶信息存入Cookie,畢竟Cookie是存在客戶端的,很不安全,一般會配合Session來使用。比如把用戶信息存到服務端的Session中,給客戶端返回SessionID,這樣一樣可以查詢出用戶信息。
下面展示Cookie在請求響應中的樣子
HTTP報文
請求和響應之間交換的信息就被稱為HTTP報文。請求方的叫做請求報文,響應方的叫做響應報文。HTTP報文大致可分為首部和主體兩部分。詳細的可見下圖
其中,請求行包含請求的方法,請求的URI和HTTP的版本。狀態行包含響應結果的狀態碼和HTTP版本,狀態碼就比如前面提到的200,它代表請求成功,更多的狀態碼和各種首部字段待會再詳說。其他則包含Cookie等信息。
HTTP狀態碼
狀態碼的職責是客戶端發送請求后,描述返回的請求結果。借助狀態碼我們就可以知道該次請求在服務端是否正常處理了。狀態碼以開頭的數字主要分為5大類:
我們只要遵循狀態碼類別的定義,即使在服務端創建自己的狀態碼都沒問題。如果要列舉每一個狀態碼,數量非常繁多,下面就介紹一下具有代表性的十幾個狀態碼。
2XX:代表成功
200 OK:表示客戶端發送的請求在服務端被正常處理。
204 No Content:表示請求已被成功處理,但在返回的響應報文中沒用返回資源。
206 Partial Content:表示客戶端進行了范圍請求,而服務器成功執行了這部分的GET請求。響應報文中包含由Content-Range指定范圍的實體內容。這里說一下,此處的范圍請求不是我們業務代碼上的范圍查詢,而是HTTP的范圍請求。在以前網速不是很快的情況下下載一個資源,可能會發生網絡中斷,如果網絡恢復的話就需要從頭下載。這時候就會想要從上次斷開的地方接着下載,那么就必須有一種請求可以支持范圍請求。比如對一份10000字節大小的資源進行范圍請求,可以只請求5001~10000字節內的資源。請求、響應報文的內容如下圖:
3XX:代表重定向
301 Moved Permanently:永久性重定向,表示請求的資源已被分配到新的URI,以后應該使用資源現在所指的URI。
302 Found:臨時性重定向,表示請求的資源已被分配到新的URI,本次請求應該使用新的URI。
303 See Other:該狀態碼功能上和302相同,但是303明確表示客戶端應該采用GET方法獲取資源。
304 Not Modified:表示資源已找到,但是不符合請求的條件。
4XX:代表客戶端錯誤
400 Bad Request:表示請求報文中存在語法錯誤,需要修改請求內容后再次發送請求。
401 Unauthorized:表示發送的請求需要通過HTTP認證。當瀏覽器初次接收到401響應時,會彈出認證用的對話窗口。
403 Forbidden:表示請求的資源被服務器拒絕了。拒絕的理由可以在主體部分進行說明。一般是沒用訪問權限才會出現這個問題。
404 Not Found:表示服務器上無法找到請求的資源。
5XX:代表服務端錯誤
500 Internal Server Error:表示服務端執行請求時發生錯誤,一般是服務端代碼出現了問題。
503 Service Unavailable:表示服務器暫時處於超負載或者正在進行停機維護。
HTTP報文首部
前面說到過,HTTP報文主要分為報文首部和主體。首部內容為客戶端和服務端分別處理請求和響應提供所需的信息。具體的信息可以往上翻一點,看看那個截圖。
HTTP首部字段是由首部字段名稱和字段值構成,中間用冒號分隔。例如:
Content-Type:text/html
Keep-Alive:timeout,max=100 (多個字段值用夠好分開)
首部字段主要分為4種類型:
通用首部字段,請求報文和響應報文兩方都會使用的首部
請求首部字段,請求報文使用的首部字段,補充了請求的附加內容、客戶端信息等信息
響應首部字段,響應報文使用的首部字段
實體首部字段,針對請求和響應報文的實體部分使用的首部字段
以上只是HTTP/1.1規范定義的47種首部字段,並不代表全部。比如常用的Cookie、Set-Cookie均未出現在其中。下面詳細說說幾個不好理解的字段。
Cache-Contro
該字段可以根據后面的字段值控制緩存行為,如上面的報文結構圖中的no-cache代表不要緩存的資源,需要源服務器的資源。該字段還有很多其他的值可供選擇,詳細的大家可以另行查詢。
Connection
該字段主要有兩個作用:控制不再轉發給代理的首部字段和管理長連接。
HTTP/1.1版本默認的連接就是長連接,之前的版本默認都是短鏈接。長連接的好處就是提高請求的效率。如果是短鏈接的話,我們每次請求資源都要進行一次TCP連接(HTTP基於TCP),也就是三次握手。請求完后斷開連接,等下次請求資源再次握手。而長連接就是建立TCP連接后短時間內不斷開,期間可以進行多次HTTP請求。
Via
該字段是為了追蹤客戶端與服務端之間的請求和響應報文的傳輸路徑。報文經過代理服務器或網關時,會現在Via字段中附加該服務器的信息,然后再進行轉發。
If-Match
帶有形如If-xxx這種形式的首部字段的請求都可稱為條件請求。服務器收到帶有附加條件的請求首先會判斷條件為真時才會執行請求。
只有當If-Match的值和Etag值一致時,服務器才會接收請求。
ETag
該字段能告訴客戶端資源的唯一標識,當資源更新時這個標識也會改變。
其他的首部字段
Set-Cookie和Cookie
下圖列舉了Set-Cookie的字段值
Cookie的使用是非常常見的,大家可以隨便打開一個網站,按F12打開調試,找到一個接口的請求,在響應首部里面應該能看到Set-Cookie字段,在請求首部應該能看到Cookie字段。Set-Cookie字段值的第一部分一般是一個字符串=另一個字符串,這就是上面的NAME=VALUE,name和value都是自定義的,然后請求時,Cookie就會帶上NAME=VALUE。
DNT
該字段屬於請求首部字段,DNT是Do Not Track的簡稱,意為拒絕個人信息被收集,是表示拒絕被精准廣告追蹤的一種方法。它的值只有0和1,0代表同意,1代表拒絕。
確保WEB安全的HTTPS
到此為止,我們了解到了HTTP優秀和方便的一面,它也有一些不足之處。如下:
- 通信沒有加密,內容可能被竊聽。
- 不驗證通信方的身份,因此有可能遭遇偽裝
- 無法證明報文的完整性,所以有可能被篡改
內容被竊聽
由於HTTP本身不具備加密(HTTP報文使用的是明文)的功能,所以也無法作到對通信整體的加密。
由於互聯網的特點,無論世界上哪個角落的服務器和客戶端進行通信,在此通信線路上的某些網絡設備都不可能是私有的,所以不排除在某個環節會遭到惡意的監聽。
而這個竊聽也並不是什么難事,比如被廣泛使用的抓包工具Wireshark就可以實現。它可以獲取HTTP協議的請求和響應的內容,並對其進行解析。這個軟件我想應該有很多人知道,不過想要用好,還是得先學好TCP協議。
雖然HTTP協議中沒有加密機制,但是可以通過和SSL或TLS的組合使用,加密HTTP的通信內容。用SSL建立安全通信線路之后,就可以在這條線路上進行HTTP通信了。與SSL組合使用的HTTP就被稱為HTTPS。
身份遭遇偽裝
HTTP協議的請求和響應不會對通信方進行確認,也就是說返回響應的並不一定是我們請求的服務器。而且任何人都可以向服務器發起請求。雖然使用HTTP協議無法確定通信方,但如果使用SSL則可以。SSL不僅提供加密,而且還使用了證書這種方法,來確認身份。證書一般由值得信任的第三方機構頒發,用以證明服務器和客戶端是實際存在的。這些所謂的值得信任的第三機構一般是社會認可的企業或者組織機構。而且偽造證書這是一件非常困難的事情。
內容被篡改
由於HTTP協議無法證明通信報文的完整性,所以在請求或響應到達對方之前,報文的內容可能會被篡改。HTTPS又是如何發現內容被篡改的,下面就會仔細說說HTTPS的工作原理。
HTTPS工作原理
前面已經說過,HTTPS其實是一個披着SSL外殼的HTTP。而另外提到的TLS可以看作是SSL的最新版本或者升級版。
在對SSL進行講解之前,我們先了解一下加密方法。SSL采用的是非對稱加密的方式。也就是說,加密是使用的是公鑰,而解密是使用的是私鑰。與之對應的是對稱加密,也就是加密和解密都是同一個密鑰,這種加密方式,我想不用說,都應該知道,運用在HTTP中依舊不安全,因為你需要把這個密鑰發送給客戶端,這個期間有可能被其他人竊聽到密鑰。
而非對稱加密,公鑰是任何人都可以知道的,而私鑰則只有服務器自己知道,這樣客戶端通過公鑰加密信息,服務端通過私鑰解密。看似很安全了,但是別忘了HTTP的一個缺點,就是內容可能會被篡改。客戶端訪問HTTPS服務器時,服務器會先把公鑰發送給客戶端,在這個過程中,如果有其他人篡改公鑰,把公鑰換成自己的,那么就失去了加密的意義。反而是服務端無法解密信息了。對於公鑰被篡改這個問題,我們待會再說,先說說HTTPS到底是怎么實現加密的。
HTTPS加密方式
HTTPS采用的是對稱和非對稱混合式的加密機制。簡單地說就是客戶端得到公鑰后,會生成一個簡單的共享密鑰,然后把共享密碼用公鑰加密發送給服務端,服務端解密后得到這個共享密鑰,之后的通信就基於這個共享密鑰進行加密通信。此時只有客戶端和服務端知道這個共享密碼,因為中途傳輸的是加密后的共享密鑰,即使被竊取了,沒有私鑰也解不開。
再接着說前面提到的,HTTPS是如何知道服務端給客戶端發送公鑰時,公鑰有沒有被篡改。前面提到了證書,是由一些機構頒發的,一般稱為CA機構。這些機構一般會有自己的私有密鑰,它會對我們服務器的公開密鑰做數字簽名,然后將這個已簽名的公開密鑰放入公鑰證書綁定在一起。到時候服務端往客戶端發送公開密鑰時,會把密鑰和數字簽名一起發送給客戶端。然后客戶端會根據CA機構的公鑰對這個數字簽名進行驗證,以確保公鑰沒有被篡改。但是你會發現,CA機構的公鑰是什么鬼,期間並沒有發送這個東西。一般這些CA機構的公鑰會內置在操作系統或者瀏覽器里,所以不需要傳輸,這樣也確保了安全性。
資料:《圖解HTTP》