首頁 > 軟體

詳細HTTP協定的前世今生

2021-06-21 16:00:24

一、前言

你知道當我們在網頁瀏覽器的位址列中輸入 URL 時,Web 頁面是如何呈現的嗎?

Web 介面當然不會憑空出來,根據 Web 瀏覽器位址列中指定的 URL,Web 使用一種名為 HTTP 的協定作為規範,完成從使用者端到伺服器端的一些流程。可以說,Web 是建立在 HTTP 協定上進行通訊的。

二、HTTP 的誕生

其實,在 1983 年 3 月之前,網際網路還只屬於少數人,全世界的網友之間的資訊是無法共用的。在這一網際網路的黎明時期,HTTP 應運而生。

歐洲核子研究組織的 Tim Berners-Lee 博士提出了一種能夠讓遠隔兩地的網友共用知識的設想,最初的理念是:藉助多檔案之間相互關聯的超文字(HyperTest),連成可相互參閱的 WWW(World Wide Web,全球資訊網)。

現在已提出了 3 項 WWW 構建技術,分別是:

  • 把 SGML(標準通用標示語言)作為頁面的文字標示語言 HTML
  • 作為檔案傳遞協定的 HTTP
  • 指定檔案所在地址的 URL

WWW 這一名稱,是 Web 瀏覽器當年用來瀏覽超文字的使用者端應用程式的名稱,現在用來表示這一系列的集合,也可簡稱為 Web。

三、什麼是 HTTP

說了這麼多,大家只知道 HTTP 很牛逼,對 HTTP 是什麼仍然沒有很直觀的概念。別急,在瞭解什麼是 HTTP 之前,我們有必要知道超文字是什麼。

HTTP 傳輸的內容就是超文字:

  • 我們先來理解「文字」:在網際網路早期的時候只是簡單的字元文字,但隨著技術的發展,現在「文字」的涵義已經可以擴充套件為圖片、視訊、壓縮包等,在 HTTP 眼裡這些都算做「文字」。
  • 再來理解「超文字」:它就是超越了普通文字的文字,它是文字、圖片、視訊等的混合體。最關鍵有超連結,能從一個超文字跳轉到另外一個超文字。

HTML 就是最常見的超文字了,它本身只是純文字檔案,但內部用很多標籤定義了圖片、視訊等的連結,在經過瀏覽器的解析,呈現給我們的就是一個文字、有畫面的網頁了。

OK,下面我們正式介紹什麼是 HTTP?

HTTP:超文字傳輸協定(HyperText Transfer Protocol)是當今網際網路上應用最為廣泛的一種網路協定。所有的 WWW(全球資訊網) 檔案都必須遵守這個標準。HTTP 和 TCP/IP 協定簇中的眾多協定一樣,用於使用者端和伺服器端之間的通訊。

四、駐足不前的 HTTP

至今被世人廣泛使用的 HTTP 協定,仍然是 20 多年前的版本。也就是說,作為 Web 檔案傳輸協定的 HTTP,它的版本幾乎沒有更新,從另一方面來說,前人的智慧真的牛逼 👍

HTTP/0.9:HTTP 於 1990 年問世,功能簡陋,僅支援 GET 請求方式,並且僅能存取 HTML 格式的資源。那時的 HTTP 並沒有作為正式的標準被建立,因此被被稱為 HTTP 0.9。

HTTP/1.0:1996 年 5 月 HTTP 正式作為標準被公佈,版本號為 HTTP 1.0。在 0.9 版本上做了進步,增加了請求方式 POST 和 HEAD;不再侷限於 0.9 版本的 HTML 格式,根據 Content-Type 可以支援多種資料格式...... 需要注意的是:1.0 版本的工作方式是短連線。雖說 HTTP/1.0 是初期標準,但該協定標準至今仍然在被廣泛使用。

HTTP/1.1:1997 年公佈的 HTTP 1.1 是目前主流的 HTTP 協定版本。當年的 HTTP 協定的出現主要是為了解決文字傳輸的難題,現在的 HTTP 早已超出了 Web 這個框架的侷限,被運用到了各種場景裡。當然,1.1 版本的最大變化,就是引入了長連線以及流水線機制(管道機制)。

這裡面出現的各種專有名詞大家留個印象就行,下文會逐漸講解。

五、區分 URL 和 URI

與 URI(統一資源識別符號) 相比,大家應該更熟悉 URL(Uniform Resource Location,統一資源定位符),URL 就是我們使用 Web 瀏覽器存取 Web 頁面時需要輸入的網頁地址。比如 http://baidu.com

URI 是 Uniform Resource Identifier 的縮寫,RFC 2386 分別對這三個單詞進行如下定義:

  • Uniform:統一規定的格式可方便處理多種不同型別的資源
  • Resource:資源的定義是可標識的任何東西。不僅可以是單一的,也可以是一個集合
  • Identifier:標識可標識的物件。也稱為識別符號

綜上,URI 就是由某個協定方法表示的資源的定位識別符號。比如說,採用 HTTP 協定時,協定方案就是 http,除此之外,還有 ftptelnet 等,標準的 URI 協定方法有 30 種左右。

URI 有兩種格式,相對 URI 和絕對 URI。

  • 相對 URI:指從瀏覽器中基本 URI 處指定的 URL,形如 /user/logo.jpg
  • 絕對 URI:使用涵蓋全部必要資訊

總結來說:URI 用字串標識某一處網際網路資源,而 URL 標識資源的地點(網際網路上所處的位置),可見 URL 是 URI 的子集。

六、HTTP 請求和響應

HTTP 協定規定,在兩臺計算機之間使用 HTTP 協定進行通訊時,在一條通訊線路上必定有一端是使用者端,另一端則是伺服器端。當在瀏覽器中輸入網址存取某個網站時, 你的瀏覽器(使用者端)會將你的請求封裝成一個 HTTP 請求傳送給伺服器站點,伺服器接收到請求後會組織響應資料封裝成一個 HTTP 響應返回給瀏覽器。換句話說,肯定是先從使用者端開始建立通訊的,伺服器端在沒有接收到請求之前不會傳送響應。

下面我們詳細分析一下 HTTP 的請求報文和響應報文

① HTTP 請求報文

HTTP 請求報文由 3 大部分組成:

1)請求行(必須在 HTTP 請求報文的第一行)

2)請求頭(從第二行開始,到第一個空行結束。請求頭和請求體之間存在一個空行)

3)請求體(通常以鍵值對 {key:value}方式傳遞資料)

舉個請求報文的例子:

請求行開頭的 POST 表示請求存取伺服器的型別,稱為方法(method)。隨後的字串 /form/login 指明瞭請求存取的資源物件,也叫做請求 URI(request-URI)。最後的 HTTP/1.1 即 HTTP 的版本號,用來提示使用者端使用的 HTTP 協定功能。

綜上來看,這段請求的意思就是:請求存取某臺 HTTP 伺服器上的 /form/login 頁面資源,並附帶引數 name = veal、age = 37。

注意,無論是 HTTP 請求報文還是 HTTP 響應報文,請求頭/響應頭和請求體/響應體之間都會有一個空行,且請求體/響應體並不是必須的。

HTTP 請求方法

請求行中的方法的作用在於可以指定請求的資源按照期望產生某種行為,即使用方法給伺服器下命令。

包括(HTTP 1.1):GETPOSTPUTHEADDELETEOPTIONSCONNECTTRACE。當然,我們在開發中最常見也最常使用的就只有前面三個。

1)GET 獲取資源

GET 方法用來請求存取已被 URI 識別的資源。指定的資源經伺服器端解析後返回響應內容

使用 GET 方法請求-響應的例子:

2)POST 傳輸實體主體

POST 主要用來傳輸資料,而 GET 主要用來獲取資源。

使用 POST 方法請求-響應的例子:

3)PUT 傳輸檔案

PUT 方法用來傳輸檔案,由於自身不帶驗證機制,任何人都可以上傳檔案,因此存在安全性問題,一般不使用該方法。

使用 PUT 方法請求-響應的例子:

4)HEAD 獲取報文首部

和 GET 方法類似,但是不返回報文實體主體部分。主要用於確認 URI 的有效性以及資源更新的日期時間等。

使用 HEAD 方法請求-響應的例子:

5)DELETE 刪除檔案

與 PUT 功能相反,用來刪除檔案,並且同樣不帶驗證機制,按照請求 URI 刪除指定的資源。

使用 DEELTE 方法請求-響應的例子:

6)OPTIONS 查詢支援的方法

用於獲取當前 URI 所支援的方法。若請求成功,會在 HTTP 響應頭中包含一個名為 「Allow」 的欄位,值是所支援的方法,如 「GET, POST」。

使用 OPTIONS 方法請求-響應的例子:

7)..........

HTTP 請求頭

請求頭用於補充請求的附加資訊、使用者端資訊、對響應內容相關的優先順序等內容。以下列出常見請求頭:

1)Referer:表示這個請求是從哪個 URI 跳過來的。。如果是直接存取就不會有這個頭。這個欄位通常用於防盜鏈。

2)Accept:告訴伺服器端,該請求所能支援的響應資料型別。(對應的,HTTP 響應報文中也有這樣一個類似的欄位 Content-Type,用於表示伺服器端傳送的資料型別,如果 Accept 指定的型別和伺服器端返回的型別不一致,就會報錯)

上圖中的 text/plain;q = 0.3 表示對於 text/plain 媒體型別的資料優先順序/權重為 0.3(q 的範圍 0 ~ 1)。不指定權重的,預設為 1.0。

資料格式型別如下圖:

3)Host:告知伺服器請求的資源所處的網際網路主機名和埠號。該欄位是 HTTP/1.1 規範中唯一一個必須被 包含在請求頭中的欄位。

4)Cookie:使用者端的 Cookie 就是通過這個報文頭屬性傳給伺服器端的!

Cookie: JSESSIONID=15982C27F7507C7FDAF0F97161F634B5

5)Connection:表示使用者端與服務連線型別;Keep-Alive 表示持久連線,close 已關閉

6)Content-Length:請求體的長度

7)Accept-Language:瀏覽器通知伺服器,瀏覽器支援的語言

8)Range:對於只需獲取部分資源的範圍請求,包含首部欄位 Range 即可告知伺服器資源的指定範圍

9)......

② HTTP響應報文

HTTP的響應報文也由三部分組成:

  • 響應行(必須在 HTTP 響應報文的第一行)
  • 響應頭(從第二行開始,到第一個空行結束。響應頭和響應體之間存在一個空行)
  • 響應體

在響應行開頭的 HTTP 1.1 表示伺服器對應的 HTTP 版本。緊隨的 200 OK 表示請求的處理結果的狀態碼和原因短語。

HTTP 狀態碼

HTTP 狀態碼負責表示使用者端 HTTP 請求的的返回結果、標記伺服器端處理是否正常、通知出現的錯誤等工作。(重中之重!!!,和我們日常開發息息相關)

狀態碼由 3 位數位組成,第一個數位定義了響應的類別:

  類別 原因短語
1xx Informational 資訊性狀態碼 接收的請求正在處理
2xx Success 成功狀態碼 請求正常處理完畢
3xx Redirection 重定向狀態碼 需要進行附加操作以完成請求
4xx Client Error 使用者端錯誤狀態碼 伺服器無法處理請求
5xx Server Error 伺服器錯誤狀態碼 伺服器處理請求出錯

 2xx:請求正常處理完畢

200 OK:使用者端請求成功

204 No Content:無內容。伺服器成功處理,但未返回內容。一般用在只是使用者端向伺服器傳送資訊,而伺服器不用向用戶端返回什麼資訊的情況。不會重新整理頁面。

206 Partial Content:伺服器已經完成了部分 GET 請求(使用者端進行了範圍請求)。響應報文中包含 Content-Range 指定範圍的實體內容

3xx:需要進行附加操作以完成請求(重定向)

  • 301 Moved Permanently:永久重定向,表示請求的資源已經永久的搬到了其他位置。
  • 302 Found:臨時重定向,表示請求的資源臨時搬到了其他位置
  • 303 See Other:臨時重定向,應使用GET定向獲取請求資源。303功能與302一樣,區別只是303明確使用者端應該使用GET存取
  • 304 Not Modified:表示使用者端傳送附帶條件的請求(GET方法請求報文中的IF…)時,條件不滿足。返回304時,不包含任何響應主體。雖然304被劃分在3XX,但和重定向一毛錢關係都沒有
  • 307 Temporary Redirect:臨時重定向,和302有著相同含義。POST不會變成GET

4xx:使用者端錯誤

  • 400 Bad Request:使用者端請求有語法錯誤,伺服器無法理解。
  • 401 Unauthorized:請求未經授權,這個狀態程式碼必須和 WWW-Authenticate 報頭域一起使用。
  • 403 Forbidden:伺服器收到請求,但是拒絕提供服務
  • 404 Not Found:請求資源不存在。比如,輸入了錯誤的 URL
  • 415 Unsupported media type:不支援的媒體型別

5xx:伺服器端錯誤,伺服器未能實現合法的請求。

  • 500 Internal Server Error:伺服器發生不可預期的錯誤。
  • 503 Server Unavailable:伺服器當前處於超負載或正在停機維護,暫時不能處理使用者端的請求,一段時間後可能恢復正常

HTTP 響應頭

響應頭也是用鍵值對 k:v,用於補充響應的附加資訊、伺服器資訊,以及對使用者端的附加要求等。

這裡著重說明一下 Location 這個欄位,可以將響應接收方引導至與某個 URI 位置不同的資源。通常來說,該欄位會配合 3xx:Redirection 的響應,提供重定向的 URI。

七、HTTP 連線管理

① 短連線(非持久連線)

在 HTTP 協定的初始版本(HTTP/1.0)中,使用者端和伺服器每進行一次 HTTP 對談,就建立一次連線,任務結束就中斷連線。當用戶端瀏覽器存取的某個 HTML 或其他型別的 Web 頁中包含有其他的 Web 資源(如JavaScript 檔案、影象檔案、CSS檔案等),每遇到這樣一個 Web 資源,瀏覽器就會重新建立一個 HTTP 對談。這種方式稱為短連線(也稱非持久連線)。

也就是說每次 HTTP 請求都要重新建立一次連線。由於 HTTP 是基於 TCP/IP 協定的,所以連線的每一次建立或者斷開都需要 TCP 三次握手或者 TCP 四次揮手的開銷。

顯然,這種方式存在巨大的弊端。比如存取一個包含多張圖片的 HTML 頁面,每請求一張圖片資源就會造成無謂的 TCP 連線的建立和斷開,大大增加了通訊量的開銷

② 長連線(持久連線)

從 HTTP/1.1 起,預設使用長連線也稱持久連線 keep-alive。使用長連線的 HTTP 協定,會在響應頭加入這行程式碼:Connection:keep-alive

在使用長連線的情況下,當一個網頁開啟完成後,使用者端和伺服器之間用於傳輸 HTTP 資料的 TCP 連線不會關閉,使用者端再次存取這個伺服器時,會繼續使用這一條已經建立的連線。Keep-Alive 不會永久保持連線,它有一個保持時間,可以在不同的伺服器軟體(如 Apache)中設定這個時間。實現長連線需要使用者端和伺服器端都支援長連線。

HTTP 協定的長連線和短連線,實質上是 TCP 協定的長連線和短連線。

③ 流水線(管線化)

預設情況下,HTTP 請求是按順序發出的,下一個請求只有在當前請求收到響應之後才會被髮出。由於受到網路延遲和頻寬的限制,在下一個請求被傳送到伺服器之前,可能需要等待很長時間。

持久連線使得多數請求以流水線(管線化 pipeline)方式傳送成為可能,即在同一條持久連線上連續發出請求,而不用等待響應返回後再傳送,這樣就可以做到同時並行傳送多個請求,而不需要一個接一個地等待響應了。

八、無狀態的 HTTP

HTTP 協定是無狀態協定。也就是說他不對之前發生過的請求和響應的狀態進行管理,即無法根據之前的狀態進行本次的請求處理。

這樣就會帶來一個明顯的問題,如果 HTTP 無法記住使用者登入的狀態,那豈不是每次頁面的跳轉都會導致使用者需要再次重新登入?

當然,不可否認,無狀態的優點也很顯著,由於不必儲存狀態,自然就減少了伺服器的 CPU 及記憶體資源的消耗。另一方面,正式由於 HTTP 簡單,所以才會被如此廣泛應用。

這樣,在保留無狀態協定這個特徵的同時,又要解決無狀態導致的問題。方案有很多種,其中比較簡單的方式就是使用 Cookie 技術。

Cookie 通過在請求和響應報文中寫入 Cookie 資訊來控制使用者端的狀態。具體來說,Cookie 會根據從伺服器端傳送的響應報文中的一個叫作 Set-Cookie 的首部欄位資訊,通知使用者端儲存 Cookie。當下次使用者端再往伺服器傳送請求時,使用者端會自動在請求報文中加入 Cookie 值傳送出去。伺服器端收到使用者端發來的 Cookie 後,會去檢查究竟是哪一個使用者端發來的連線請求,然後對比伺服器上的記錄,最後得到之前的狀態資訊。

形象來說,在使用者端第一次請求後,伺服器會下發一個裝有客戶資訊的身份證,後續使用者端請求伺服器的時候,帶上身份證,伺服器就能認得了。

下圖展示了發生 Cookie 互動的情景:

1)沒有 Cookie 資訊狀態下的請求:

對應的 HTTP 請求報文(沒有 Cookie 資訊的狀態)

GET /reader/ HTTP/1.1

Host: baidu.com

* 首部欄位沒有 Cookie 的相關資訊

對應的 HTTP 響應報文(伺服器端生成 Cookie 資訊)

HTTP/1.1 200 OK

Date: Thu, 12 Jul 2020 15:12:20 GMT

Server: Apache

<Set-Cookie: sid=1342077140226; path=/; expires=Wed, 10-Oct-12 15:12:20 GMT>

Content-Type: text/plain; charset=UTF-8

2)第 2 次以後的請求(存有 Cookie 資訊狀態)

對應的 HTTP 請求報文(自動傳送儲存著的 Cookie 資訊)

GET /image/ HTTP/1.1

Host: baidu.com

Cookie: sid=1342077140226

九、HTTP 斷點續傳

所謂斷點續傳指的是下載傳輸檔案可以中斷,之後重新下載時可以接著中斷的地方開始下載,而不必從頭開始下載。斷點續傳需要使用者端和伺服器端都支援。

這是一個非常常見的功能,原理很簡單,其實就是 HTTP 請求頭中的欄位 Range 和響應頭中的欄位 Content-Range 的簡單使用。使用者端一塊一塊的請求資料,最後將下載回來的資料塊拼接成完整的資料。打個比方,瀏覽器請求伺服器上的一個服務,所發出的請求如下:

假設伺服器域名為www.baidu.com,檔名為 down.zip。

GET /down.zip HTTP/1.1 

Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/vnd.ms- 

excel, application/msword, application/vnd.ms-powerpoint, */* 

Accept-Language: zh-cn 

Accept-Encoding: gzip, deflate 

User-Agent: Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0) 

Connection: Keep-Alive 

伺服器收到請求後,按要求尋找請求的檔案,提取檔案的資訊,然後返回給瀏覽器,返回資訊如下:

200 

Content-Length=106786028 

Accept-Ranges=bytes 

Date=Mon, 30 Apr 2001 12:56:11 GMT 

ETag=W/"02ca57e173c11:95b" 

Content-Type=application/octet-stream 

Server=Microsoft-IIS/5.0 

Last-Modified=Mon, 30 Apr 2001 12:56:11 GMT 

OK,那麼既然要斷點續傳,使用者端瀏覽器請求伺服器的時候要多加一條資訊 — 從哪裡開始請求資料。 比如要求從 2000070 位元組開始:

GET /down.zip HTTP/1.0 

User-Agent: NetFox 

RANGE: bytes=2000070- 

Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2 

仔細看一下就會發現多了一行 RANGE: bytes=2000070-。這一行的意思就是告訴伺服器 down.zip 這個檔案從 2000070 位元組開始傳,前面的位元組不用傳了。

伺服器收到這個請求以後,返回的資訊如下:

206

Content-Length=106786028

Content-Range=bytes 2000070-106786027/106786028

Date=Mon, 30 Apr 2001 12:55:20 GMT

ETag=W/"02ca57e173c11:95b"

Content-Type=application/octet-stream

Server=Microsoft-IIS/5.0

Last-Modified=Mon, 30 Apr 2001 12:55:20 GMT

和前面伺服器返回的資訊比較一下,就會發現增加了一行: Content-Range=bytes 2000070-106786027/106786028。返回的程式碼也改為 206 了,而不再是 200 了。

十、HTTP 的缺點

到現在為止,我們已經瞭解到了 HTTP 具有相當優秀和方便的一面,然後,事務皆有兩面性,他也是有不足之處的:

通訊使用明文(不加密),內容可能被竊聽

不驗證通訊對方的身份,因此有可能遭遇偽裝

無法證明報文的完整性,所以有可能被篡改

這些問題不僅在 HTTP 上出現,其他未加密的協定中也存在類似問題,為了解決 HTTP 的痛點,HTTPS 應用而生,說白了 HTTP + 加密 + 認證 + 完整性保護就是 HTTPS 協定,關於 HTTPS 協定的內容也非常之多且重要,後續會單開一篇文章進行講解。

以上就是詳細HTTP協定的前世今生的詳細內容,更多關於HTTP協定的資料請關注it145.com其它相關文章!


IT145.com E-mail:sddin#qq.com