HTTP协议

**超文本傳輸協定**（英語：**H**yper**T**ext **T**ransfer **P**rotocol，縮寫：**HTTP**）是一種用於分佈式、協作式和超媒體訊息系統的應用層協定。HTTP 是全球資訊網的數據通信的基礎。

設計 HTTP 最初的目的是為了提供一種發布和接收 HTML 頁面的方法。透過 HTTP 或者 HTTPS 協定請求的資源由統一資源識別碼（Uniform Resource Identifiers，URI）來標識。

HTTP 的發展是由提姆・柏內茲 - 李於 1989 年在歐洲核子研究組織（CERN）所發起。HTTP 的標準制定由全球資訊網協會（World Wide Web Consortium，W3C）和網際網路工程任務組（Internet Engineering Task Force，IETF）進行協調，最終發布了一系列的 RFC，其中最著名的是 1999 年 6 月公佈的 RFC 2616，定義了 HTTP 協定中現今廣泛使用的一個版本 ——HTTP 1.1。

2014 年 12 月，網際網路工程任務組（IETF）的 Hypertext Transfer Protocol Bis（httpbis）工作小組將 HTTP/2 標準提議遞交至 IESG 進行討論，於 2015 年 2 月 17 日被批准。 HTTP/2 標準於 2015 年 5 月以 RFC 7540 正式發表，取代 HTTP 1.1 成為 HTTP 的實作標準。

## 協定概述

HTTP 是一個客戶端（使用者）和伺服器端（網站）之間請求和應答的標準，通常使用 TCP 協定。透過使用網頁瀏覽器、網路爬蟲或者其它的工具，客戶端發起一個 HTTP 請求到伺服器上指定埠（預設埠為 80）。我們稱這個客戶端為使用者代理程式（user agent）。應答的伺服器上儲存著一些資源，比如 HTML 檔案和圖像。我們稱這個應答伺服器為源伺服器（origin server）。在使用者代理和源伺服器中間可能存在多個「中間層」，比如代理伺服器、閘道器或者隧道（tunnel）。

儘管 TCP/IP 協定是網際網路上最流行的應用，但是在 HTTP 協定中並沒有規定它必須使用或它支援的層。事實上 HTTP 可以在任何網際網路協定或其他網路上實作。HTTP 假定其下層協定提供可靠的傳輸。因此，任何能夠提供這種保證的協定都可以被其使用，所以其在 TCP/IP 協定族使用 TCP 作為其傳輸層。

通常，由 HTTP 客戶端發起一個請求，建立一個到伺服器指定埠（預設是 80 埠）的 TCP 連線。HTTP 伺服器則在那個埠監聽客戶端的請求。一旦收到請求，伺服器會向客戶端返回一個狀態，比如 "HTTP/1.1 200 OK"，以及返回的內容，如請求的檔案、錯誤訊息、或者其它訊息。

## 請求方法

HTTP/1.1 協定中共定義了八種方法（也叫「動作」）來以不同方式操作指定的資源：

**GET**
: 向指定的資源發出「顯示」請求。使用 GET 方法應該只用在讀取資料，而不應當被用於產生「副作用」的操作中，例如在網路應用程式中。其中一個原因是 GET 可能會被網路爬蟲等隨意存取。參見安全方法。瀏覽器直接發出的 GET 只能由一個 url 觸發。GET 上要在 url 之外帶一些參數就只能依靠 url 上附帶 querystring。

**HEAD**
: 與 GET 方法一樣，都是向伺服器發出指定資源的請求。只不過伺服器將不傳回資源的本文部份。它的好處在於，使用這個方法可以在不必傳輸全部內容的情況下，就可以取得其中「關於該資源的 y 資訊」（元資訊或稱元資料）。

**POST**
: 向指定資源提交資料，請求伺服器進行處理（例如提交表單或者上傳檔案）。資料被包含在請求本文中。這個請求可能會建立新的資源或修改現有資源，或二者皆有。每次提交，表單的資料被瀏覽器用編碼到 HTTP 請求的 body 里。瀏覽器發出的 POST 請求的 body 主要有兩種格式，一種是 application/x-www-form-urlencoded 用來傳輸簡單的資料，大概就是 "key1=value1&key2=value2" 這樣的格式。另外一種是傳檔案，會採用 multipart/form-data 格式。採用後者是因為 application/x-www-form-urlencoded 的編碼方式對於檔案這種二進位的資料非常低效。

**PUT**
: 向指定資源位置上傳其最新內容。

**DELETE**
: 請求伺服器刪除 Request-URI 所標識的資源。

**TRACE**
: 回顯伺服器收到的請求，主要用於測試或診斷。

**OPTIONS**
: 這個方法可使伺服器傳回該資源所支援的所有 HTTP 請求方法。用 '\*' 來代替資源名稱，向 Web 伺服器傳送 OPTIONS 請求，可以測試伺服器功能是否正常運作。

**CONNECT**
: HTTP/1.1 協定中預留給能夠將連接改為隧道方式的代理伺服器。通常用於 SSL 加密伺服器的連結（經由非加密的 HTTP 代理伺服器）。

方法名稱是區分大小寫的。當某個請求所針對的資源不支援對應的請求方法的時候，伺服器應當返回狀態碼 405（Method Not Allowed），當伺服器不認識或者不支援對應的請求方法的時候，應當返回狀態碼 501（Not Implemented）。

**HTTP 伺服器至少應該實作 GET 和 HEAD 方法**，其他方法都是可選的。當然，所有的方法支援的實作都應當符合下述的方法各自的語意定義。

此外，特定的 HTTP 伺服器還能夠擴充自訂的方法。例如：

**PATCH（由 RFC 5789 指定的方法）**
: 用於將局部修改應用到資源。

### 安全方法

對於 GET 和 HEAD 方法而言，除了進行取得資源訊息外，這些請求不應當再有其他意義。也就是說，這些方法應當被認為是「安全的」。
客戶端可能會使用其他「非安全」方法，例如 POST，PUT 及 DELETE，應該以特殊的方式（通常是按鈕而不是超連結）告知客戶可能的後果（例如一個按鈕控制的資金交易），或請求的操作可能是不安全的（例如某個檔案將被上傳或刪除）。

但是，不能想當然地認為伺服器在處理某個 GET 請求時不會產生任何副作用。事實上，很多動態資源會把這作為其特性。這裡重要的區別在於使用者並沒有請求這一副作用，因此不應由使用者為這些副作用承擔責任。

### 副作用

假如在不考慮諸如錯誤或者過期等問題的情況下，若干次請求的副作用與單次請求相同或者根本沒有副作用，那麼這些請求方法就能夠被視作「冪等 (idempotence)」的。GET，HEAD，PUT 和 DELETE 方法都有這樣的冪等屬性，同樣由於根據協定，OPTIONS，TRACE 都不應有副作用，因此也理所當然也是冪等的。

假如一個由若干請求組成的請求序列產生的結果，在重複執行這個請求序列或者其中任何一個或多個請求後仍沒有發生變化，則這個請求序列便是「冪等」的。但是，可能出現一個由若干請求組成的請求序列是「非冪等」的，即使這個請求序列中所有執行的請求方法都是冪等的。例如，這個請求序列的結果依賴於某個會在下次執行這個序列的過程中被修改的變數。

### 對照表

## 版本

超文本傳輸協定已經演化出了很多版本，它們中的大部分都是向下相容的。在 RFC 2145 中描述了 HTTP 版本號的用法。客戶端在請求的開始告訴伺服器它採用的協定版本號，而後者則在回應中採用相同或者更早的協定版本。

### HTTP/0.9

已過時。只接受 GET 一種請求方法，沒有在通訊中指定版本號，且不支援請求頭。由於該版本不支援 POST 方法，因此客戶端無法向伺服器傳遞太多訊息。

### HTTP/1.0

這是第一個在通訊中指定版本號的 HTTP 協定版本。

### HTTP/1.1

預設採用持續連接（Connection: keep-alive），能很好地配合代理伺服器工作。還支援以管道方式在同時傳送多個請求，以便降低線路負載，提高傳輸速度。

HTTP/1.1 相較於 HTTP/1.0 協定的區別主要體現在：

* 快取處理
* 頻寬最佳化及網路連接的使用
* 錯誤通知的管理
* 訊息在網路中的傳送
* 網際網路位址的維護
* 安全性及完整性

### HTTP/2

目前版本，於 2015 年 5 月作為網際網路標準正式發布。

### HTTP/3

最新版本，於 2022 年 6 月 6 日標準化為 RFC9114。會拋棄使用 TCP，透過 UDP 上使用 QUIC 來承載應用層資料。

## 狀態碼

所有 HTTP 回應的第一行都是**狀態行**，依次是當前 HTTP 版本號，3 位數字組成的狀態代碼，以及描述狀態的短語，彼此由空格分隔。

狀態代碼的第一個數字代表當前回應的類型：

* 1xx 訊息 —— 請求已被伺服器接收，繼續處理
* 2xx 成功 —— 請求已成功被伺服器接收、理解、並接受
* 3xx 重新導向 —— 需要後續操作才能完成這一請求
* 4xx 請求錯誤 —— 請求含有詞法錯誤或者無法被執行
* 5xx 伺服器錯誤 —— 伺服器在處理某個正確請求時發生錯誤

雖然 RFC 2616 中已經推薦了描述狀態的短語，例如 "200 OK"，"404 Not Found"，但是 WEB 開發者仍然能夠自行決定採用何種短語，用以顯示在地化的狀態描述或者自訂訊息。

## 持續連線

在 HTTP 0.9 和 1.0 中，TCP 連線在每一次請求 / 回應對之後關閉。在 HTTP 1.1 中，引入了保持連線的機制，一個連接可以重複在多個請求 / 回應使用。持續連線的方式可以大大減少等待時間，因為在發出第一個請求後，雙方不需要重新執行 TCP 交握程式。

HTTP 1.1 還改進了 HTTP 1.0 的頻寬。 例如，HTTP 1.1 引入了分塊傳輸編碼，以允許傳遞內容可以在持續連線上被串流傳輸而不必使用到緩衝器。HTTP 管道允許客戶端在收到每個回應之前發送多個請求，進一步減少使用者感受到的滯後時間。協定的另一個補充是位元組服務，允許客戶端請求資源的某一部份，伺服器僅回應某資源的指明部分。

## 協定例子

下面是一個 HTTP 客戶端與伺服器之間對談的例子，執行於 www.google.com，埠 80

### 請求訊息

發出的請求訊息（message request）包括以下幾個:

* 請求行（例如 GET /images/logo.gif HTTP/1.1，表示從 /images 目錄下請求 logo.gif 這個檔案）
* 請求頭（例如 Accept-Language: en）
* 空行
* 其他訊息體

請求行和標題必須以 <CR><LF> 作為結尾。空行內必須只有 <CR><LF> 而無其他空格。在 HTTP/1.1 協定中，所有的請求頭，除 Host 外，都是可選的。

### 客戶端請求

（末尾有一個空行。第一行指定方法、資源路徑、協定版本；第二行是在 1.1 版里必帶的一個 header 作用於指定主機）

### 伺服器應答

（緊跟著一個空行，並且由 HTML 格式的文字組成了 Google 的首頁）

在 HTTP1.0，單一 TCP 連線內僅執行一個「客戶端傳送請求 — 伺服器傳送應答」周期，之後釋放 TCP 連線。在 HTTP1.1 最佳化支援持續活躍連接：客戶端連續多次傳送請求、接收應答；批次多請求時，同一 TCP 連線在活躍（Keep-Live）間期內復用，避免重複 TCP 初始交握活動，減少網路負荷和回應周期。此外支援應答到達前繼續傳送請求（通常是兩個），稱為「流線化」（stream）。

## 類似協定

Gopher 是 1990 年代早期被 HTTP 取代的內容傳遞協定。SPDY 是 Google 開發的 HTTP 的替代方案，它被新版本的 HTTP 協定 HTTP/2 所取代。

## 參見

* HTTP 基本認證
* 內容協商
* .har
* HTTP 摘要認證
* HTTP 壓縮
* HTTP/2
* HTTPS
* HTTP 頭欄位
* HTTP 狀態碼
* 表現層狀態轉換（REST）
* 頁庫存檔
* WebSocket
* Wireshark

## 參考

## 外部連結

* Change History for HTTP. W3.org. [2010-08-01]. （原始內容存檔於 2021-05-06）.
* Design Issues for HTTP. W3.org. [2010-08-01]. （原始內容存檔於 2021-03-01）.
* Classic HTTP Documents. W3.org. 1998-05-14 [2010-08-01]. （原始內容存檔於 2021-05-05）.