目錄
02-2. HTTP 請求與回應
⏱️ 閱讀時間: 12 分鐘 🎯 難度: ⭐⭐ (簡單)
🎯 本篇重點
深入理解 HTTP 請求和回應的結構、常用標頭的意義、如何使用開發者工具觀察,以及實際應用範例。
🤔 什麼是 HTTP 請求和回應?
一句話解釋: HTTP 請求就像是「訂餐單」,HTTP 回應就像是「外送餐點」。
你(瀏覽器) → 餐廳(伺服器)
請求(訂餐單):
- 餐廳名稱(Host)
- 餐點名稱(URL)
- 訂餐方式(Method)
- 特殊需求(Headers)
- 備註(Body)
回應(外送餐點):
- 訂單狀態(Status Code)
- 餐點內容(Body)
- 包裝資訊(Headers)📤 HTTP 請求(Request)結構
完整結構
GET /api/users/123 HTTP/1.1 ← 1️⃣ 請求行(Request Line)
Host: api.example.com ← 2️⃣ 標頭(Headers)
User-Agent: Mozilla/5.0
Accept: application/json
Authorization: Bearer TOKEN123
Content-Type: application/json
Connection: keep-alive
← 3️⃣ 空行(必須)
{"update": "data"} ← 4️⃣ 主體(Body,可選)1️⃣ 請求行(Request Line)
GET /api/users/123 HTTP/1.1
↑ ↑ ↑
方法 路徑 版本
組成部分:
1. HTTP 方法(Method)
- GET, POST, PUT, DELETE...
2. 請求路徑(Request URI)
- /api/users/123
- 可以包含查詢參數:/search?q=keyword&page=1
3. HTTP 版本
- HTTP/1.1(最常用)
- HTTP/2
- HTTP/32️⃣ 請求標頭(Request Headers)
Host(必須)
Host: www.example.com
說明:
- 指定目標伺服器的域名和埠號
- HTTP/1.1 必須包含
- 支援虛擬主機(一個 IP 多個域名)
範例:
Host: www.example.com
Host: www.example.com:8080User-Agent
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64)
AppleWebKit/537.36 Chrome/120.0.0.0
說明:
- 客戶端的瀏覽器資訊
- 伺服器可以根據不同瀏覽器回傳不同內容
實際用途:
- 行動版網站判斷(iPhone、Android)
- 瀏覽器相容性處理
- 統計分析
範例:
// 桌面版 Chrome
User-Agent: Mozilla/5.0 (Windows NT 10.0) Chrome/120.0
// 行動版 Safari
User-Agent: Mozilla/5.0 (iPhone; CPU iPhone OS 17_0)Accept
Accept: text/html, application/json, */*
說明:
- 客戶端可以接受的內容類型
- 伺服器根據此決定回傳格式
常見值:
Accept: text/html - 網頁
Accept: application/json - JSON 資料
Accept: image/* - 任何圖片
Accept: */* - 任何類型
多個類型(優先順序):
Accept: text/html, application/json;q=0.9, */*;q=0.8
q=0.9:品質因子(優先順序 0-1)Authorization
Authorization: Bearer eyJhbGci0iJIUzI1NiIsInR5cCI6IkpXVCJ9...
說明:
- 身份驗證資訊
- 通常用於 API 認證
常見類型:
1. Basic(基本認證)
Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=
(username:password 的 Base64 編碼)
2. Bearer(Token 認證)
Authorization: Bearer TOKEN123
(通常是 JWT)
3. OAuth
Authorization: OAuth oauth_token="xxx"Content-Type
Content-Type: application/json; charset=utf-8
說明:
- 請求主體的內容類型
- 只在有 Body 時需要(POST、PUT)
常見值:
Content-Type: application/json - JSON 資料
Content-Type: application/x-www-form-urlencoded - 表單
Content-Type: multipart/form-data - 檔案上傳
Content-Type: text/plain - 純文字
Content-Type: text/html - HTMLCookie
Cookie: sessionid=abc123; user_pref=dark_mode
說明:
- 儲存在客戶端的資料
- 每次請求自動帶上
- 用於保持登入狀態
範例:
Cookie: sessionid=abc123; token=xyz789; lang=zh-twReferer
Referer: https://www.google.com/
說明:
- 來源頁面 URL
- 告訴伺服器從哪個頁面連過來的
用途:
- 統計分析(流量來源)
- 防盜連(檢查來源)
- 除錯(追蹤用戶路徑)3️⃣ 空行
必須有一個空行分隔標頭和主體
即使沒有主體也要有空行4️⃣ 請求主體(Request Body)
說明:
- 傳送給伺服器的資料
- GET、HEAD、DELETE 通常沒有 Body
- POST、PUT、PATCH 通常有 Body
範例 1:JSON 格式
POST /api/users HTTP/1.1
Content-Type: application/json
{
"name": "John Doe",
"email": "john@example.com",
"age": 30
}
範例 2:表單格式
POST /login HTTP/1.1
Content-Type: application/x-www-form-urlencoded
username=john&password=123456
範例 3:檔案上傳
POST /upload HTTP/1.1
Content-Type: multipart/form-data; boundary=----Boundary
------Boundary
Content-Disposition: form-data; name="file"; filename="photo.jpg"
Content-Type: image/jpeg
[二進位圖片資料]
------Boundary--📥 HTTP 回應(Response)結構
完整結構
HTTP/1.1 200 OK ← 1️⃣ 狀態行(Status Line)
Date: Mon, 06 Jan 2025 12:00:00 GMT ← 2️⃣ 標頭(Headers)
Server: Apache/2.4.41
Content-Type: application/json
Content-Length: 1234
Cache-Control: max-age=3600
Set-Cookie: sessionid=abc123
Connection: keep-alive
← 3️⃣ 空行(必須)
{ ← 4️⃣ 主體(Body)
"id": 123,
"name": "John Doe"
}1️⃣ 狀態行(Status Line)
HTTP/1.1 200 OK
↑ ↑ ↑
版本 狀態碼 原因短語
組成部分:
1. HTTP 版本
- HTTP/1.1
2. 狀態碼(Status Code)
- 200(成功)
- 404(找不到)
- 500(伺服器錯誤)
3. 原因短語(Reason Phrase)
- OK
- Not Found
- Internal Server Error2️⃣ 回應標頭(Response Headers)
Content-Type
Content-Type: application/json; charset=utf-8
說明:
- 回應主體的內容類型
- 客戶端根據此解析內容
常見值:
Content-Type: application/json - JSON 資料
Content-Type: text/html - HTML 網頁
Content-Type: text/plain - 純文字
Content-Type: image/jpeg - JPEG 圖片
Content-Type: application/pdf - PDF 文件Content-Length
Content-Length: 1234
說明:
- 回應主體的位元組數
- 客戶端知道要讀取多少資料
範例:
Content-Length: 0 - 沒有內容
Content-Length: 12345 - 12345 bytesSet-Cookie
Set-Cookie: sessionid=abc123; HttpOnly; Secure; Max-Age=3600
說明:
- 伺服器設定 Cookie
- 客戶端儲存並在後續請求帶上
屬性:
Set-Cookie: name=value;
Domain=.example.com; - 有效域名
Path=/; - 有效路徑
Expires=Wed, 09 Jun 2025 10:18:14 GMT; - 過期時間
Max-Age=3600; - 存活秒數
HttpOnly; - 禁止 JavaScript 存取(防 XSS)
Secure; - 只在 HTTPS 傳送
SameSite=Strict - 防 CSRF 攻擊
範例:
Set-Cookie: sessionid=abc123; HttpOnly; Secure
Set-Cookie: lang=zh-tw; Max-Age=31536000Cache-Control
Cache-Control: max-age=3600, public
說明:
- 控制快取行為
- 減少重複請求
常見值:
Cache-Control: no-cache - 每次都重新驗證
Cache-Control: no-store - 完全不快取
Cache-Control: max-age=3600 - 快取 1 小時
Cache-Control: public - 可被公共快取(CDN)
Cache-Control: private - 只能被瀏覽器快取
Cache-Control: must-revalidate - 過期後必須重新驗證
組合使用:
Cache-Control: public, max-age=31536000
(公共快取,快取 1 年)Server
Server: Apache/2.4.41 (Unix)
說明:
- 伺服器軟體資訊
常見值:
Server: Apache/2.4.41
Server: nginx/1.20.1
Server: Microsoft-IIS/10.0
Server: cloudflareLocation
Location: https://www.example.com/new-page
說明:
- 重新導向的目標 URL
- 通常搭配 3xx 狀態碼
範例:
HTTP/1.1 301 Moved Permanently
Location: https://www.example.com/new-url
HTTP/1.1 302 Found
Location: https://www.example.com/temp-urlAccess-Control-Allow-Origin(CORS)
Access-Control-Allow-Origin: *
說明:
- 跨來源資源共用(CORS)
- 允許哪些域名存取資源
常見值:
Access-Control-Allow-Origin: *
(允許所有域名)
Access-Control-Allow-Origin: https://www.example.com
(只允許特定域名)
搭配其他 CORS 標頭:
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Max-Age: 864004️⃣ 回應主體(Response Body)
說明:
- 伺服器回傳的實際內容
- 可以是 HTML、JSON、圖片等
範例 1:JSON 回應
HTTP/1.1 200 OK
Content-Type: application/json
{
"status": "success",
"data": {
"id": 123,
"name": "John Doe"
}
}
範例 2:HTML 回應
HTTP/1.1 200 OK
Content-Type: text/html
<!DOCTYPE html>
<html>
<head><title>首頁</title></head>
<body>Hello World!</body>
</html>
範例 3:錯誤回應
HTTP/1.1 404 Not Found
Content-Type: application/json
{
"error": "User not found",
"message": "The requested user does not exist"
}🔍 完整範例:註冊新用戶
請求(Request)
POST /api/users HTTP/1.1
Host: api.example.com
User-Agent: Mozilla/5.0 (Windows NT 10.0)
Accept: application/json
Content-Type: application/json
Authorization: Bearer eyJhbGci...
Connection: keep-alive
Content-Length: 123
{
"username": "john_doe",
"email": "john@example.com",
"password": "SecurePass123",
"age": 30
}回應(Response)- 成功
HTTP/1.1 201 Created
Date: Mon, 06 Jan 2025 12:00:00 GMT
Server: nginx/1.20.1
Content-Type: application/json
Content-Length: 456
Location: /api/users/123
Set-Cookie: sessionid=abc123; HttpOnly; Secure
Cache-Control: no-store
Connection: keep-alive
{
"status": "success",
"message": "User created successfully",
"data": {
"id": 123,
"username": "john_doe",
"email": "john@example.com",
"created_at": "2025-01-06T12:00:00Z"
}
}回應(Response)- 失敗
HTTP/1.1 400 Bad Request
Date: Mon, 06 Jan 2025 12:00:00 GMT
Server: nginx/1.20.1
Content-Type: application/json
Content-Length: 234
{
"status": "error",
"message": "Validation failed",
"errors": {
"email": ["Email already exists"],
"password": ["Password must be at least 8 characters"]
}
}💻 使用開發者工具觀察 HTTP
Chrome DevTools
步驟 1:打開開發者工具
- Windows: F12 或 Ctrl+Shift+I
- Mac: Cmd+Option+I
步驟 2:切換到 Network 分頁
步驟 3:重新載入網頁(Ctrl+R / Cmd+R)
步驟 4:點選任一請求,查看詳細資訊
可以看到:
├─ General(概要)
│ ├─ Request URL
│ ├─ Request Method
│ ├─ Status Code
│ └─ Remote Address
│
├─ Request Headers(請求標頭)
│ ├─ Host
│ ├─ User-Agent
│ └─ Cookie
│
├─ Response Headers(回應標頭)
│ ├─ Content-Type
│ ├─ Set-Cookie
│ └─ Cache-Control
│
├─ Request Payload(請求資料)
└─ Response(回應內容)使用 curl 測試
# 基本 GET 請求
curl https://api.example.com/users/123
# 顯示回應標頭
curl -I https://api.example.com/users/123
# POST 請求(JSON)
curl -X POST https://api.example.com/users \
-H "Content-Type: application/json" \
-H "Authorization: Bearer TOKEN" \
-d '{"name":"John","email":"john@example.com"}'
# 顯示完整的請求和回應
curl -v https://api.example.com/users/123
# 輸出範例:
> GET /users/123 HTTP/1.1
> Host: api.example.com
> User-Agent: curl/7.68.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Content-Type: application/json
< Content-Length: 123
<
{"id":123,"name":"John"}🌐 實際應用場景
場景 1:登入流程
【步驟 1:發送登入請求】
POST /api/login HTTP/1.1
Host: api.example.com
Content-Type: application/json
{
"username": "john",
"password": "123456"
}
【步驟 2:伺服器驗證並回應】
HTTP/1.1 200 OK
Set-Cookie: sessionid=abc123; HttpOnly; Secure
Content-Type: application/json
{
"status": "success",
"token": "eyJhbGci...",
"user": {
"id": 123,
"username": "john"
}
}
【步驟 3:後續請求帶上認證資訊】
GET /api/profile HTTP/1.1
Host: api.example.com
Cookie: sessionid=abc123
Authorization: Bearer eyJhbGci...
【步驟 4:伺服器驗證並回傳資料】
HTTP/1.1 200 OK
Content-Type: application/json
{
"id": 123,
"username": "john",
"email": "john@example.com"
}場景 2:檔案上傳
【請求】
POST /api/upload HTTP/1.1
Host: api.example.com
Content-Type: multipart/form-data; boundary=----Boundary123
Content-Length: 123456
------Boundary123
Content-Disposition: form-data; name="file"; filename="photo.jpg"
Content-Type: image/jpeg
[二進位圖片資料]
------Boundary123
Content-Disposition: form-data; name="description"
My vacation photo
------Boundary123--
【回應】
HTTP/1.1 201 Created
Content-Type: application/json
Location: /api/files/456
{
"status": "success",
"file": {
"id": 456,
"filename": "photo.jpg",
"url": "https://cdn.example.com/photos/456.jpg",
"size": 123456
}
}場景 3:分頁查詢
【請求】
GET /api/articles?page=2&per_page=10&sort=date&order=desc HTTP/1.1
Host: api.example.com
Accept: application/json
【回應】
HTTP/1.1 200 OK
Content-Type: application/json
X-Total-Count: 95
X-Page: 2
X-Per-Page: 10
Link: </api/articles?page=1>; rel="first",
</api/articles?page=3>; rel="next",
</api/articles?page=10>; rel="last"
{
"data": [
{
"id": 11,
"title": "文章標題 11",
"created_at": "2025-01-05"
},
{
"id": 12,
"title": "文章標題 12",
"created_at": "2025-01-04"
}
...
],
"pagination": {
"current_page": 2,
"per_page": 10,
"total": 95,
"total_pages": 10
}
}🎓 面試常見問題
Q1:GET 請求可以有 Body 嗎?
A:理論上可以,但不建議
RFC 7231 規範:
- GET 請求可以包含 Body
- 但語義上 GET 是「取得」資源
- 不應該傳送資料
實際問題:
1. 許多伺服器會忽略 GET 的 Body
2. 中間的代理伺服器可能丟棄 Body
3. 快取機制通常不考慮 Body
4. 瀏覽器和工具可能不支援
正確做法:
- 查詢參數放在 URL:GET /search?q=keyword
- 需要傳送資料用 POST
錯誤示範:
GET /search HTTP/1.1
{"query": "keyword"} ← 不建議
正確示範:
GET /search?q=keyword HTTP/1.1Q2:Content-Type 和 Accept 的差異?
A:方向相反
Content-Type(我傳送的內容類型):
- 請求:告訴伺服器「我傳的是什麼格式」
- 回應:告訴客戶端「我回傳的是什麼格式」
Accept(我想要的內容類型):
- 請求:告訴伺服器「我想要什麼格式」
- 回應:(不使用)
範例 1:POST 請求
POST /api/users HTTP/1.1
Content-Type: application/json ← 我傳送的是 JSON
Accept: application/json ← 我想要收到 JSON
{"name": "John"}
HTTP/1.1 201 Created
Content-Type: application/json ← 我回傳的是 JSON
{"id": 123, "name": "John"}
範例 2:內容協商
GET /api/users/123 HTTP/1.1
Accept: application/json ← 我想要 JSON
HTTP/1.1 200 OK
Content-Type: application/json ← 伺服器回傳 JSON
GET /api/users/123 HTTP/1.1
Accept: application/xml ← 我想要 XML
HTTP/1.1 200 OK
Content-Type: application/xml ← 伺服器回傳 XMLQ3:Cookie 和 Session 的差異?
A:儲存位置不同
Cookie(儲存在客戶端):
- 資料存在瀏覽器
- 每次請求自動帶上
- 有大小限制(4KB)
- 可以設定過期時間
- 可能被竄改(不安全)
範例:
Set-Cookie: user_pref=dark_mode; Max-Age=31536000
Cookie: user_pref=dark_mode
Session(儲存在伺服器):
- 資料存在伺服器
- 只在伺服器端儲存 Session ID
- 無大小限制
- 更安全(資料不外洩)
運作流程:
1. 用戶登入成功
2. 伺服器建立 Session
- Session ID: abc123
- Session 資料: {user_id: 123, name: "John"}
3. 伺服器回傳 Session ID(透過 Cookie)
Set-Cookie: sessionid=abc123
4. 客戶端後續請求帶上 Cookie
Cookie: sessionid=abc123
5. 伺服器根據 Session ID 查詢 Session 資料
abc123 → {user_id: 123, name: "John"}
優缺點:
Cookie:
✅ 減輕伺服器負擔
❌ 不安全(可被竄改)
❌ 有大小限制
Session:
✅ 安全(資料在伺服器)
✅ 無大小限制
❌ 增加伺服器負擔
❌ 難以擴展(分散式系統)Q4:如何處理 CORS 錯誤?
A:伺服器端設定 CORS 標頭
什麼是 CORS?
- Cross-Origin Resource Sharing(跨來源資源共用)
- 瀏覽器安全機制
- 防止惡意網站存取其他網站的資料
錯誤訊息:
Access to fetch at 'https://api.example.com' from origin
'https://www.mysite.com' has been blocked by CORS policy
原因:
- 瀏覽器發現是跨域請求
- 伺服器沒有回傳 CORS 標頭
- 瀏覽器阻擋回應
解決方法(伺服器端):
方法 1:允許所有域名
Access-Control-Allow-Origin: *
方法 2:允許特定域名
Access-Control-Allow-Origin: https://www.mysite.com
方法 3:完整設定
Access-Control-Allow-Origin: https://www.mysite.com
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Allow-Credentials: true
Access-Control-Max-Age: 86400
Python (Flask) 範例:
from flask import Flask
from flask_cors import CORS
app = Flask(__name__)
CORS(app, origins="https://www.mysite.com")
Node.js (Express) 範例:
const cors = require('cors');
app.use(cors({
origin: 'https://www.mysite.com'
}));
注意:
- CORS 是瀏覽器的限制
- curl、Postman 不受影響
- 開發時可以暫時關閉瀏覽器 CORS 檢查(不建議)Q5:Authorization 標頭有哪些常見方式?
A:主要有 Basic、Bearer、OAuth
1. Basic Authentication(基本認證)
Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=
編碼方式:
Base64(username:password)
範例:
username: john
password: secret123
→ john:secret123
→ Base64 編碼
→ am9objpzZWNyZXQxMjM=
缺點:
❌ 不安全(只是編碼,不是加密)
❌ 必須搭配 HTTPS
❌ 每次請求都要傳送密碼
2. Bearer Token(Token 認證)
Authorization: Bearer eyJhbGci0iJIUzI1NiIsInR5cCI6IkpXVCJ9...
流程:
1. 用戶登入 → 伺服器回傳 Token(通常是 JWT)
2. 客戶端儲存 Token
3. 後續請求帶上 Token
優點:
✅ 不用每次傳送密碼
✅ Token 可以設定過期時間
✅ Token 可以包含用戶資訊(JWT)
JWT 結構:
eyJhbGci... .eyJ1c2VyX... .SflKxwRJ...
↑ ↑ ↑
Header Payload Signature
(演算法) (用戶資料) (簽名)
3. OAuth 2.0
Authorization: Bearer ACCESS_TOKEN
流程:
1. 用戶授權(例:用 Google 登入)
2. 取得 Access Token
3. 使用 Access Token 存取 API
範例:
Authorization: Bearer ya29.a0AfH6SMBx...
實務建議:
- API 認證:用 Bearer Token(JWT)
- 第三方登入:用 OAuth 2.0
- 內部系統:可以用 Basic(搭配 HTTPS)
- 避免在 URL 傳送 Token(會被記錄)✅ 重點回顧
HTTP 請求結構:
請求行 + 標頭 + 空行 + 主體HTTP 回應結構:
狀態行 + 標頭 + 空行 + 主體重要請求標頭:
- Host - 目標伺服器(必須)
- User-Agent - 客戶端資訊
- Accept - 接受的內容類型
- Authorization - 身份驗證
- Content-Type - 請求內容類型
- Cookie - 儲存的資料
重要回應標頭:
- Content-Type - 回應內容類型
- Set-Cookie - 設定 Cookie
- Cache-Control - 快取控制
- Location - 重新導向目標
- Access-Control-Allow-Origin - CORS 設定
面試重點:
- ✅ GET 不建議有 Body
- ✅ Content-Type(我傳的)vs Accept(我要的)
- ✅ Cookie(客戶端)vs Session(伺服器)
- ✅ CORS 需要伺服器設定標頭
- ✅ Authorization 有 Basic、Bearer、OAuth
上一篇: 02-1. HTTP 基礎概念 下一篇: 02-3. HTTP 方法(GET、POST、PUT、DELETE)
最後更新:2025-01-06