HTTP 協定#
HTTP(HyperText Transfer Protocol)是應用層協定,是 Web 通信的基礎。本章涵蓋 HTTP 報文結構、請求方法、狀態碼、頭字段和連接管理。
HTTP 基礎#
請求-回應模型#
HTTP 採用經典的請求-回應模型:
sequenceDiagram
participant C as 客戶端(瀏覽器)
participant S as 伺服器
C->>S: HTTP 請求<br/>GET /index.html
S->>C: HTTP 回應<br/>200 OK + HTML 內容一次完整的訪問過程#
- DNS 解析:域名轉換為 IP 地址
- TCP 三次握手:建立連接
- 發送 HTTP 請求:構建並發送請求報文
- 伺服器處理:解析請求,處理業務邏輯
- 返回 HTTP 回應:構建並發送回應報文
- 瀏覽器渲染:解析 HTML/CSS/JS,顯示頁面
HTTP 報文結構#
報文組成#
HTTP 報文由 Header + Body 組成:
| 組成部分 | 說明 | 是否必須 |
|---|---|---|
| 起始行(請求行/狀態行) | 請求方法或狀態碼 | 必須 |
| 頭字段 | Key: Value 格式的元資料 | 必須 |
| 空行(CRLF) | 分隔 Header 和 Body | 必須 |
| 消息正文(Body) | 實際傳輸的資料 | 可選 |
HTTP 報文必須有 Header,但可以沒有 Body。Header 和 Body 之間必須有空行(CRLF)。
請求報文範例#
GET /api/users HTTP/1.1
Host: www.example.com
User-Agent: Mozilla/5.0
Accept: application/json
Accept-Language: zh-TW,zh;q=0.9,en;q=0.8
Connection: keep-alive回應報文範例#
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Content-Length: 128
Date: Mon, 26 Jan 2026 08:00:00 GMT
Connection: keep-alive
{"users": [{"id": 1, "name": "Alice"}]}請求方法#
常用方法#
| 方法 | 語義 | 安全性 | 冪等性 | Body |
|---|---|---|---|---|
| GET | 獲取資源 | 安全 | 冪等 | 無 |
| HEAD | 獲取元資訊 | 安全 | 冪等 | 無 |
| POST | 提交資料/創建資源 | 不安全 | 非冪等 | 有 |
| PUT | 替換資源 | 不安全 | 冪等 | 有 |
| DELETE | 刪除資源 | 不安全 | 冪等 | 可選 |
| PATCH | 部分更新資源 | 不安全 | 非冪等 | 有 |
| OPTIONS | 查詢支援的方法 | 安全 | 冪等 | 無 |
安全與冪等的含義
- 安全(Safe):不會修改伺服器上的資源
- 冪等(Idempotent):執行多次和執行一次效果相同
理解冪等性可以類比 SQL:
POST像INSERT:多次執行會創建多條記錄PUT像UPDATE:多次執行結果相同
GET vs POST#
| 特性 | GET | POST |
|---|---|---|
| 資料位置 | URL 查詢參數 | Body |
| 資料長度 | 受 URL 長度限制 | 無限制 |
| 快取 | 可快取 | 不可快取 |
| 歷史記錄 | 會保存 | 不會保存 |
| 書籤 | 可收藏 | 不可收藏 |
| 語義 | 讀取資料 | 提交資料 |
狀態碼#
狀態碼分類#
| 分類 | 範圍 | 含義 |
|---|---|---|
| 1xx | 100-199 | 資訊性,處理中 |
| 2xx | 200-299 | 成功 |
| 3xx | 300-399 | 重定向 |
| 4xx | 400-499 | 客戶端錯誤 |
| 5xx | 500-599 | 伺服器錯誤 |
常見狀態碼#
2xx 成功
| 狀態碼 | 名稱 | 說明 |
|---|---|---|
| 200 | OK | 請求成功 |
| 201 | Created | 資源創建成功(POST 後) |
| 204 | No Content | 成功但無返回內容 |
| 206 | Partial | 部分內容(範圍請求) |
3xx 重定向
| 狀態碼 | 名稱 | 說明 |
|---|---|---|
| 301 | Moved Permanently | 永久重定向 |
| 302 | Found | 臨時重定向 |
| 304 | Not Modified | 未修改(快取有效) |
4xx 客戶端錯誤
| 狀態碼 | 名稱 | 說明 |
|---|---|---|
| 400 | Bad Request | 請求格式錯誤 |
| 401 | Unauthorized | 未認證 |
| 403 | Forbidden | 禁止訪問 |
| 404 | Not Found | 資源不存在 |
| 405 | Method Not Allowed | 方法不允許 |
| 429 | Too Many Requests | 請求過多 |
5xx 伺服器錯誤
| 狀態碼 | 名稱 | 說明 |
|---|---|---|
| 500 | Internal Error | 伺服器內部錯誤 |
| 502 | Bad Gateway | 網關錯誤 |
| 503 | Service Unavailable | 服務不可用 |
| 504 | Gateway Timeout | 網關超時 |
301 是永久重定向(如 HTTP 跳轉 HTTPS),瀏覽器會快取;302 是臨時重定向,每次都會請求原地址。
常用頭字段#
通用頭字段#
| 字段 | 說明 | 範例 |
|---|---|---|
Date | 報文創建時間 | Date: Mon, 26 Jan 2026 08:00:00 GMT |
Connection | 連接管理 | Connection: keep-alive |
Cache-Control | 快取控制 | Cache-Control: max-age=3600 |
請求頭字段#
| 字段 | 說明 | 範例 |
|---|---|---|
Host | 目標主機(必須) | Host: www.example.com |
User-Agent | 客戶端資訊 | User-Agent: Mozilla/5.0... |
Accept | 可接受的 MIME 類型 | Accept: text/html,application/json |
Accept-Encoding | 可接受的壓縮格式 | Accept-Encoding: gzip, deflate, br |
Accept-Language | 可接受的語言 | Accept-Language: zh-TW,en |
Cookie | 攜帶 Cookie | Cookie: session=abc123 |
Authorization | 認證資訊 | Authorization: Bearer token... |
回應頭字段#
| 字段 | 說明 | 範例 |
|---|---|---|
Content-Type | 內容類型 | Content-Type: text/html; charset=utf-8 |
Content-Length | 內容長度 | Content-Length: 1024 |
Content-Encoding | 內容編碼 | Content-Encoding: gzip |
Set-Cookie | 設置 Cookie | Set-Cookie: session=abc; HttpOnly |
Location | 重定向地址 | Location: https://new.example.com |
內容協商#
客戶端和伺服器協商返回最合適的內容:
# 請求
Accept: text/html,application/json;q=0.9,*/*;q=0.8
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-TW,zh;q=0.9,en;q=0.8
# 回應
Content-Type: text/html; charset=utf-8
Content-Encoding: gzip
Content-Language: zh-TWq 值表示優先級權重,範圍 0-1,默認為 1。
q=0表示不接受。
連接管理#
短連接 vs 長連接#
短連接(HTTP/1.0 默認)
sequenceDiagram
participant C as 客戶端
participant S as 伺服器
C->>S: 建立連接
C->>S: 請求1
S->>C: 回應1
C->>S: 關閉連接
C->>S: 建立連接
C->>S: 請求2
S->>C: 回應2
C->>S: 關閉連接長連接(HTTP/1.1 默認)
sequenceDiagram
participant C as 客戶端
participant S as 伺服器
C->>S: 建立連接
C->>S: 請求1
S->>C: 回應1
C->>S: 請求2
S->>C: 回應2
C->>S: 請求3
S->>C: 回應3
Note over C,S: 連接保持,可繼續請求| 特性 | 短連接 | 長連接 |
|---|---|---|
| 連接開銷 | 每次請求都要三次握手 | 一次握手,多次請求 |
| 效率 | 低 | 高 |
| 伺服器資源 | 每次釋放 | 需要維護連接狀態 |
| 適用場景 | 低頻請求 | 高頻請求 |
連接控制#
# 請求使用長連接(HTTP/1.1 默認)
Connection: keep-alive
# 請求關閉連接
Connection: close伺服器可以設置長連接策略:
# Nginx 組態
keepalive_timeout 60; # 空閒超時 60 秒
keepalive_requests 100; # 最多處理 100 個請求隊頭阻塞問題#
HTTP/1.1 的長連接是串行的,前面的請求阻塞會影響後面的請求:
請求 A(耗時 5s)→ 請求 B(等待)→ 請求 C(等待)
阻塞! 阻塞!隊頭阻塞是 HTTP/1.1 的固有缺陷,無法完全解決。HTTP/2 通過多路復用解決了這個問題。
緩解策略#
| 策略 | 說明 |
|---|---|
| 並發連接 | 同一域名開多個連接(瀏覽器限制 6-8 個) |
| 域名分片 | 多個域名指向同一伺服器,繞過連接數限制 |
| 資源合併 | CSS/JS 合併,減少請求數 |
| 雪碧圖 | 多個小圖合併為一張大圖 |
資料傳輸#
壓縮傳輸#
# 請求告知支援的壓縮格式
Accept-Encoding: gzip, deflate, br
# 回應告知使用的壓縮格式
Content-Encoding: gzip常用壓縮算法:
| 算法 | 特點 |
|---|---|
| gzip | 最常用,兼容性好 |
| deflate | 較老的算法 |
| br (Brotli) | Google 開發,壓縮率更高 |
分塊傳輸#
用於不知道內容總長度的情況:
HTTP/1.1 200 OK
Transfer-Encoding: chunked
7\r\n
Mozilla\r\n
9\r\n
Developer\r\n
0\r\n
\r\n
Transfer-Encoding: chunked和Content-Length互斥,不能同時使用。
範圍請求#
支援斷點續傳和多線程下載:
# 請求部分內容
GET /video.mp4 HTTP/1.1
Range: bytes=0-1023
# 回應
HTTP/1.1 206 Partial Content
Content-Range: bytes 0-1023/10240
Content-Length: 1024常用工具#
# curl 發送請求
curl -v https://example.com
curl -X POST -d '{"name":"test"}' -H "Content-Type: application/json" https://api.example.com
# 查看回應頭
curl -I https://example.com
# httpie(更友好的 HTTP 客戶端)
http GET https://example.com
http POST https://api.example.com name=test本章小結#
| 概念 | 關鍵點 |
|---|---|
| 報文結構 | Header + 空行 + Body,Header 必須,Body 可選 |
| 請求方法 | GET 讀取,POST 提交,PUT 替換,DELETE 刪除 |
| 狀態碼 | 2xx 成功,3xx 重定向,4xx 客戶端錯誤,5xx 伺服器錯誤 |
| 頭字段 | Host 必須,Accept/Content-Type 協商內容類型 |
| 連接管理 | HTTP/1.1 默認長連接,但有隊頭阻塞問題 |
| 資料傳輸 | 支援壓縮、分塊、範圍請求 |