JackHttp -- 從原理來理解 HTTP

JackHttp 系列的介紹


在介紹 HTTP 之前,首先我們來思考幾個問題

  1. HTTP 到底是什麼?
  2. HTTP 在整個網絡通信中扮演着怎樣的角色?
  3. HTTP 是如何進行通信的呢?

帶着這 3 個問題 ,我們來開始今天的內容。(當然,如果大神對這3個問題比較清楚,可以直接跳到末文看總結)。

在理解 HTTP 之前,首先我們得先來看看 TCP/IP 協議族是什麼?

簡介TCP/IP

定義:

TCP/IP(Transmission Control Protocol/Internet Protocol,傳輸控制協議/網際協議)是指能夠在多個不同網絡間實現信息傳輸的協議簇。TCP/IP 協議不僅僅指的是 TCP 和 IP 兩個協議,而是指一個由 FTP、SMTP、TCP、UDP、IP 等協議構成的協議簇, 只是因爲在TCP/IP 協議中 TCP 協議和 IP 協議最具代表性,所以被稱爲TCP/IP協議。

看上面的描述一大堆,不需要死記硬背,我們只需要有一個概念,也就是 TCP/IP 的本質。

本質:

一系列協議所組成的一個網絡分層模型。

哦,,搞半天你是個協議族,還分層?分幾層 ?爲啥子要分層?

具體分層:

OSI 七層模型 TCP/IP 模型 功能 TCP/IP 具體包含的協議
應用層 應用層 文件傳輸,電子郵件,文件服務,虛擬終端 TFTP,HTTP,SMMP,FTP,SMTP,DNS,Telnet
表示層 應用層 數據格式化,代碼轉換,數據加密 沒有協議
會話層 應用層 接觸或建立與別的接點的聯繫 沒有協議
傳輸層 傳輸層 提供端到端的接口 TCP,UDP
網絡層 網絡層 爲數據包選擇路由 IP,ICMP,RIP,OSPF,BCP,ICMP
數據鏈路層 鏈路層 傳輸由地址的幀以及錯誤功能檢測 SLIP,CSLIP,PPP,ARP,RARP,MTU
物理層 鏈路層 以二進制數據形式在物理媒體上傳輸數據 ISO2110,IEEE802,IEEE802.2

簡單的看這個圖似乎好像有些複雜,這裏我們只需要瞭解三點:

  1. TCP/IP 的分層是從開放系統互聯 OSI (Open System Interconnection)模型演變而來的。
  2. TCP/IP 與 OSI 在分層模塊上有些區別,OSI 參考模型注重“通信協議必要的功能是什麼”,而 TCP/IP 則更強調“在計算機上實現協議應該開發哪種程序”。
  3. 在 TCP/IP 協議中,它們被簡化爲了四層.分別是應用層、傳輸層、網絡層、鏈路層

知道以上信息再結合我們實際的開發,其實上面這個表可再以優化一下,把我們常用的協議取出,如下:

TCP/IP 模型 TCP/IP 具體包含的協議
應用層 HTTP,FTP,DNS
傳輸層 TCP,UDP
網絡層 IP
數據鏈路層 路由,WIFI

這樣看就簡潔多了吧,OK,回到之前我們的疑問,我們現在大致瞭解了 TCP/IP 協議族確實需要分層,並且是分四層,那麼,重點來了?到底爲什麼需要分層呢?

核心原因,主要是網絡的不可靠性,或者說是網絡的不穩定造成的。 假設我們的網絡是穩定可靠的,那麼應用層軟件其實可以直接和鏈路層設備進行通信,哪還需要中間這麼複雜的過程。其中 TCP 協議的三次握手和他的窗口(吞吐量)也主要是來處理網絡的不穩定和不可靠性的,後面的文章中會講到。另外分層的次要原因還考慮到安全、節約寬帶、方便管理等。

弄明白上面幾個問題後,我們對 HTTP 在網絡通信中扮演的角色已經有了一個初步的瞭解。讀到這裏我們可以對本文開頭的第二個問題進行回答了,哦!!!,原來 HTTP 在整個網絡通信(TCP/IP 協議族)中屬於應用層的一個協議,用於和傳輸層進行通信。

那麼到底什麼是 HTTP?

我們平時感受到 HTTP 比較直觀的是兩個場景

  1. 在我們遊覽器地址欄啪輸入“www.jackwaiting.com”,啪,一個界面出來了。
  2. 在我們編寫軟件程序的時候,拿到後臺的一個接口。例如:“https://www.jackwaiting.com?xxx=“xxx” ” 然後對這個 HTTP 請求做一系列的描述,什麼請求方法咯,GET/POST , 請求行,請求 Body,返回碼,XXXX 一大堆,對吧?

定義:

HTTP 是超文本傳輸協議(HyperText Transfer Protocol)。

注意:Hyper 這裏的“超”指的是“拓展”的意思,不是“超級”的意思。

超文本?

解釋:再我們屏幕前看到的文本中,含有可以跳轉到其它文本鏈接的文本。

怎麼去理解呢,例如我們這篇博客,在開頭定義了一個 “JackHttp 系列的介紹”的超鏈接,可以跳轉到另外一個鏈接對吧?那麼是不是就是說 “JackHttp 系列的介紹”就是超本文呢?可以這麼說,但是,,,,,我們這整篇文章也可以說成是超文本,編寫這篇博客的工具MarkDown 也能稱之爲超文本,甚至是顯示的代碼 HTML 也含有這種能力,也能稱之爲超文本,能明白嗎?也就是小到一個網絡請求的文本 “http://www.baidu.com” ,大到一個 HTML,凡是含有可以跳轉到其它文本鏈接的文本,都能稱之爲超文本。

爲什麼定義 HTTP,其目的是什麼?

我儘量用我的理解來解釋清楚:兩個陌生的機器要交換數據,就像我們人與人之間一樣,我們需要“租房、購房、吃飯,購物上網”等等行爲,“租房我們需要簽訂合同,購房不僅需要簽訂合同,風險比較大,還需要在政府備案網籤,HTTPS?吃飯商家也會提供一個菜單,購物我們用戶和淘寶其實也會簽訂《用戶協議》《用戶隱私協議》,有注意到吧?淘寶與商家也會遵循彼此簽訂的協議”。這些日常生活中的行爲視乎都有一個協議再約束我們,如果哪一方不按照彼此的協議做事情,就會有對應的懲罰,表現在計算機裏的就會給不同的端進行報錯。
那麼定義 HTTP 協議目的就是爲了規定客戶端和服務端 數據傳輸的格式數據交互行爲 ,定義好了 HTTP 協議,客戶端與服務端之間溝通起來將會更加方便,省力,省帶寬。

HTTP 工作原理

饒了這麼大的圈,有點感覺了,哦!!!,客戶端想和某服務器進行通信,需要給服務器發送一個超本文?

在這裏插入圖片描述

萬丈高樓平地起! 我們按照 HTTP 協議說的方式在遊覽器中做一個簡單的 HTTP 請求試試,在地址欄輸入“http://jackwaiting.com”, 通過按 F12 追蹤看看發送的是一個怎樣的超文本。

在這裏插入圖片描述
從這個圖中,我們能挖出哪些信息呢,比較直觀的:

  1. 發送一個超文本似乎需要包含 Headers、Preview、Response、Cookies、Timing
  2. 在 Headers 中還包含 General, Response Headers , Request Headers
  3. 觀察地址欄發現會跳轉到 “https://blog.csdn.net/zhanggang740”, 並不是我們輸入的 “http://jackwaiting.com”, 細心點看你會發現在 Headers ->General 用一個黃色小圓球標記了一個 Status Code 301? 並且在 Headers -> Response Headers -> Location 中找到"https://blog.csdn.net/zhanggang740",此時我們隱隱的感覺到似乎跳轉到了"https://blog.csdn.net/zhanggang740"。

在這裏插入圖片描述
what fuck? 又來了個307?跳到了https? 還沒有結束?四連問,我們在往下看。
在這裏插入圖片描述
咦,狀態碼變綠了?返回 200?

看到這裏,如果此時你是一個 Android 程序猿,似乎找到一絲熟悉感,這不就是平時收到服務器返回給我的響應碼?但仔細一想平時我做網絡請求時也重來沒寫過這麼多的請求 Headers,也沒有收到過什麼 301,307 更不會察覺到還建立了 https 的連接,這很正常。

其實如果在我們 APP 中發送“http://jackwaiting.com”這個請求,同樣會經歷上面的所有過程,只是在 Android 中, okhttp 已經幫我們做了這些事情而已。

我簡單的說一下,暫時你只需要瞭解即可,當 okhttp 的攔截器接收到“http://jackwaiting.com”請求到來時,會逐步依次調用如下攔截器
RetryAndFollowUpInterceptor
BridgeInterceptor
CacheInterceptor
ConnectInterceptor
CallServerInterceptor

在我們這個例子中 RetryAndFollowUpInterceptor 會對我們的重定向異常 301、307 進行攔截,重新再次發送請求,BridgeInterceptor 會幫我們補充請求過程中所需要的 Headers 信息
ConnectInterceptor 會去建立 TCP Connect、SSL 連接(HTTPS 連接),然後通過CallServerInterceptor 發射請求,直到接收到響應 200 的狀態碼,此次 HTTP 請求結束,大概是如下流程:

在這裏插入圖片描述
所以作爲前端程序員可能只會感知到服務器返回的 200,中間的內容無法察覺,或者說不關心,那是因爲 Okhttp 幫我們實現了,這裏看不懂也沒關係,後期會詳解 Okhttp 的工作原理和源碼。

搞明白了這個過程,在來分析上面的那幾張圖剩下的內容:

  1. Preview 是這個請求後服務器返回給我們內容預覽,很直觀的感覺到,這不是協議所要求的。
  2. Response 是服務器返回的 “https://blog.csdn.net/zhanggang740” HTML 文本以此來展示網頁內容,是你,沒得跑。
  3. Cookies 保存着一些屬性值,暫時不知道是幹嘛的
  4. Timing 記錄的是一些連接時間,請求時間等。似乎也是一些可視化內容,我們不需要關心。

從這次請求我們似乎可以觀察到客戶端發送一個請,客戶端還會返回一個響應,中間會有一些Header,Cookes 等信息,如下圖
在這裏插入圖片描述
我們對上圖再次進行拆分,瞭解其本質

  1. 客戶端是如何把一個"http://jackwaiting.com" 轉換成一個請求的,轉換的標準是什麼?
  2. 一個轉換後的標準是如何發送到服務器的?
  3. 服務器返回的響應是怎樣的標準?
  4. 響應標準怎樣返回到客戶端?

URL -> HTTP 報文

報文(message)是網絡中交換與傳輸的數據單元,即站點一次性要發送的數據塊。報文包含了將要發送的完整的數據信息,其長短很不一致,長度不限且可變。

格式標準

在理解格式標準前,我先簡單說明一下,本文將使用 HTPP 1.1 的格式標準來講解,原因如下:

  1. HTTP 發展至今,已經衍生出了多個版本,從 HTTP 0.9 -> HTTP 1.0 -> HTTP 1.1 -> SPDY 協議 -> HTTP 2.0 。其中 HTTP 1.0 由於默認是短連接,每次與服務器交互,都需要新開一個連接,至今基本已經被棄用了。(1.0 都棄用了,0.9 不用說啦吧)。
  2. SPDY 協議是 HTTP 2.0 的基礎, HTTP 2.0 在市場上還沒有完全普及,在部分手機的兼容性上還沒有完全適配。
  3. HTTP 2.0 協議的格式和 HTTP 1.1 雖然完全不同了,但實際上 HTTP 2.0 並沒有改變 HTTP 1.1 的語義,只是把原來 HTTP 1.1 的 Header 和 Body 部分用 Frame 重新封裝了一層而已。

那麼一個 HTTP 1.1 報文具體長什麼樣子?

        Request       = Request-Line              ; Section 5.1
                        *(( general-header        ; Section 4.5
                         | request-header         ; Section 5.3
                         | entity-header ) CRLF)  ; Section 7.1
                        CRLF
                        [ message-body ]          ; Section 4.3

這是一個典型的請求報文,從報文格式中可以看出,一個 Request 請求包含 4 部分

  • 請求行(Request - Line)
  • 請求頭 ( general-header| request-header| entity-header )
  • 空行( CRLF)
  • 請求體(message-body)

那麼,這 4 個部分具體都包含哪些內容呢?

請求行(Request - Line)

常用的請求行包含 請求資源的方法,請求資源的路徑(相對路徑、絕對路徑),使用的協議版本 3 個部分,如下:

    1、Request-URI    = "*" | absoluteURI | abs_path | authority

其中請求方法主要包含
GET:獲取資源(不帶Body)
POST:傳輸實體主體(帶Body)
PUT:傳輸資源文件
DELETE:刪除資源文件
HEAD:獲得此次請求的報文首部
TRACE:追蹤路徑
CONNECT:保留
OPTIONS:詢問支持的方法

例如我們本文的 URL “http://blog.csdn.net/zhanggang740” 轉換成請求行就是這個樣子,其中第一種更爲常見。

    第一種格式
    GET /zhanggang740 HTTP/1.1
	Host: blog.csdn.net

    第二種
    GET http://blog.csdn.net/zhanggang740 HTTP/1.1
     Host: www.haust.edu.cn

請求頭( Request-header)

我們接下來對一些重要的請求頭做一些分享。

Host

請求資源所在的服務器。

Accept

Accept 代表客戶端希望接受的數據類型。
常見的媒體格式類型如下:

媒體類型 格式
text/html HTML 格式
text/plain 純文本格式
text/xml XML 格式
image/gif GIF 圖片格式
image/jpeg JPG 圖片格式
image/png PNG 圖片格式
application/xhtml+xml XHTML 格式
application/xml XML 數據格式
application/atom+xml ATOM XML 聚合格式
application/json JSON 數據格式
application/pdf PDF 格式
application/msword WORD 文檔格式
application/octet-stream 二進制流數據(如常見的文件下載)
application/x-www-form-urlencoded 普通表單,Encoded URL 格式 ,只能傳文本,不能傳二進制數據
multipart/form-data 多部分形式,一版用於傳輸包含二進制內容的多項內容

跟Accept 相關的幾個Header。

Header 說明
Accept-Charset 聲明瀏覽器支持的字符集
Accept-Encoding 聲明客戶端支持的編碼類型的
Accept-Langulage 聲明客戶端支持的語言

Referer

HTTP Referer 是 Header 的一部分,當客戶端向服務器發送請求的時候,一般會帶 Referer 告訴服務器該請求是從哪裏鏈接過來的,服務器因此可以獲得一些信息用於處理。

Referrer Policy

Referrer 用於記錄這次請求的來源。
目前最新的 Referrer Policy 規定了五種 Referrer 策略:

No Referrer When Downgrade
僅當發生協議降級(如 HTTPS 頁面引入 HTTP 資源,從 HTTPS 頁面跳到 HTTP 等)時不發送 Referrer 信息。
Origin Only
發送只包含 Host 部分的 Referrer。啓用這個規則,無論是否發生協議降級,
無論是本站鏈接還是站外鏈接,都會發送 Referrer 信息,但是隻包含協議 + host 部分(不包含具體的路徑及參數等信息)。
Origin When Cross-origin
僅在發生跨域訪問時發送只包含 Host 的 Referrer,同域下還是完整的。
它與 Origin Only 的區別是多判斷了是否 Cross-origin。需要注意的是協議、域名和端口都一致,纔會被瀏覽器認爲是同域。
Unsafe URL。
無論是否發生協議降級,無論是本站鏈接還是站外鏈接,統統都發送 Referrer 信息。正如其名,這是最寬鬆而最不安全的策略。
No Referrer :
任何情況下都不發送 Referrer 信息。

Pragma

Pragma 是 HTTP 1.1 之前版本的歷史遺留字段,僅作爲與 HTTP 的向後兼容而定義。

Origin

用於指明當前請求來自於哪個站點。

Cache-Control

Cache-Control 指定了請求和響應遵循的緩存機制。其中 Request Header 的 Cache-Control 包含如方式:

no-cache
不要讀取緩存中的文件,要求向服務器重新請求。
no-store
請求和響應都禁止被緩存。
max-age
表示當訪問此網頁後的 max-age 秒內再次訪問不會去服務器請求,其功能與 Expires 類似。只是 Expires 是根據某個特定日期值做比較。一但緩存者自身的時間不準確.則結果可能就是錯誤的。而 max-age 沒有這種問題,所以使用過程中儘量優先使用 max-age。
max-stale
允許讀取過期時間必須小於 max-stale 值的緩存對象。
min-fresh
接受其 max-age 生命期大於其當前時間跟 min-fresh 值之和的緩存對象。
only-if-cached
告知緩存者,我希望內容來自緩存,我並不關心被緩存響應,是否是新鮮的。
no-transform
告知代理,不要更改媒體類型。

Connection

HTTP Connection 允許在請求處理結束之後將 TCP 連接保持在打開狀態,以便爲未來的HTTP 請求重用現存的連接。

keep-alive
開啓 HTTP 持久連接,HTTP 1.1 默認值。
close
關閉 HTTP 持久連接,HTTP 1.0 默認值。
timeout
連接多久後關閉,關閉後,有請求,需要重新建立連接。

User-Agent

User-Agent 首部包含了一個特徵字符串,用來讓網絡協議的對端來識別發起請求的用戶代理軟件的應用類型、操作系統、軟件開發商、版本號。

空行(CRLF)

特別要注意:Request Head 後面必須有一個單獨的空白行 CLRF (Carriage-Return Line-Feed回車換行\r\n),否則格式會非法,或被服務器認爲不完整,等待CRLF發送過去。

請求體(message-body)

具體需要發送請求的 body 內容。

返回響應

服務器返回的響應報文,原理基本和請求時一致,包含狀態行、響應頭部、空行和響應包體,其中狀態行包含響應協議、狀態碼、描述 4 個部分組成。

我們重點關注響應頭和響應碼 2 個部分:

響應頭部(Response Header)

Content-Type

代表服務端返回的數據類型,格式跟請求頭 Accept 基本支持格式一致,就不詳細介紹了。

Content-Encoding

服務器發送的數據使用的壓縮格式。

Content-Length

服務器發送的數據的大小(單位:字節)。

Content-Language

服務器發送的數據使用的自然語言。

Location

配合狀態碼爲 3XX 時請求重定向。

Server

服務器的基本信息,如如服務器應用程序軟件的名稱、版本。

Last-Modified

被請求的當前資源最後修改時間

Cache-Control(重點)

public
數據內容皆被儲存起來,就連有密碼保護的網頁也儲存,安全性很低。
private
數據內容只能被儲存到私有的cache,僅對某個用戶有效,不能共享。
no-cache
可以緩存,但是隻有跟服務器驗證了其有效後,才能返回給客戶端。
no-store
請求和響應都禁止被緩存。
max-age
本響應包含的對象的過期時間。
max-stale
允許讀取過期時間必須小於 max-stale 值的緩存對象。
must-revalidate
如果緩存過期了,會再次和原來的服務器確定是否爲最新數據。
proxy-revalidate
與 must-revalidate 類似,區別在於:proxy-revalidate 要排除掉用戶代理的緩存的。即其規則並不應用於用戶代理的本地緩存上。
s-maxage:
與 max-age 的唯一區別 是, s-maxage僅僅應用於共享緩存.而不應用於用戶代理的本地緩存。 一版情況下 s-maxage 的優先級要高於 max-age。
no-transform
告知代理,不要更改媒體類型。

響應碼(狀態碼)

響應碼大全
響應碼大全份上,當然,如果你懶得點,我也幫你羅列席常見的響應碼。

狀態碼 原因短語 代表含義 HTTP 版本
200 OK (成功) 請求成功 HTTP/0.9 可用
301 Moved Permanently(永久移動) 該狀態碼錶示所請求的 URI 資源路徑已經改變,新的 URL 會在響應的Location:頭字段裏找到. HTTP/0.9 可用
307 Temporary Redirect(臨時重定向) 服務器發送該響應用來引導客戶端使用相同的方法訪問另外一個 URI 來獲取想要獲取的資源.新的 URL 會在響應的 Location :頭字段裏找到.與 302 狀態碼有相同的語義,且前後兩次訪問必須使用相同的方法 (GET POST). HTTP/1.1 可用
404 Not Found (未找到) 服務器找不到所請求的資源.由於經常發生此種情況,所以該狀態碼在上網時是非常常見的. HTTP/0.9 可用
500 Internal Server Error (內部服務器錯誤) 服務器遇到未知的無法解決的問題. HTTP/0.9 可用

對拆分問題進行解答:

客戶端是如何把一個 “http://jackwaiting.com” 轉換成一個請求的,轉換的標準是什麼?
上面定義的報文就是我們我們 URL 轉換成 Request 請求的標準,也稱之爲轉換協議。
至於具體 http://jackwaiting.com 如何 轉換成一個 報文,在 Android 中,okHttp 的攔截器做了工作,在 Request 請求發射之前,對請求行,請求頭(可選),空行,請求body(可選) 進行的純代碼拼接,本文主要疏通 HTTP 部分,okhttp 源碼後續講解。
一個轉換後的標準是如何發送到服務器的?
HTTP 在這個過程中其實什麼都沒做,僅僅只是提供了一個協議規範,保證我們的數據能正常的對接給 TCP,進行拆包傳輸。
服務器返回的響應是怎樣的標準?
報文嘛(有沒有發現解答越來越簡單?)
響應標準怎樣返回到客戶端?
逆向思維嘛,你自己想。

總結一句話:
HTTP 定義的是一個客戶端和服務器端通信的規範和標準,在整個網絡通信中其實沒有幹具體的實事,只是讓客戶端與服務端之間溝通起來更加方便,省力,省帶寬,就像是我們生活中的租房合同、購房合同,菜單 ^ . ^

發佈了38 篇原創文章 · 獲贊 152 · 訪問量 33萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章