跳至主要內容
Skip to content

HTTP Methods(上):GET 與 POST 的本質差異

GET 與 POST 是 HTTP 中最常用的兩個方法,但它們的差異遠不止「GET 用來取資料、POST 用來送資料」這麼簡單。本文將從協定規範的角度,深入探討它們的本質差異。


一、 HTTP Methods 概述

HTTP 方法(Method)定義了客戶端希望對資源執行的操作類型。RFC 9110 定義了以下標準方法:

方法用途安全冪等
GET獲取資源
HEAD獲取標頭(不含 Body)
POST提交資料
PUT替換資源
PATCH部分更新
DELETE刪除資源
OPTIONS查詢支援的方法
TRACE迴路測試
CONNECT建立隧道

> **安全(Safe)**:該操作不會改變伺服器上的資源狀態。

冪等(Idempotent):多次執行相同操作,結果都一樣。


二、 GET 方法深入解析

2.1 規範定義

根據 RFC 9110:

GET 方法請求轉移目標資源的當前選定的表示

簡單來說:GET 就是「給我看看這個資源目前的樣子」。

2.2 GET 的特性

安全性(Safe)

GET 請求不應該產生副作用。這意味著:

✅ 正確用法:
GET /api/users/123        → 查詢用戶資料
GET /api/articles?page=2  → 獲取文章列表

❌ 錯誤用法:
GET /api/users/123/delete → 不應該用 GET 來刪除
GET /api/cart/checkout    → 結帳會產生副作用

WARNING

雖然技術上你可以用 GET 來修改資料,但這違反了 HTTP 語義,可能導致:

  • 瀏覽器/代理隨意重送請求
  • 搜尋引擎爬蟲誤觸發操作
  • 預取(Prefetch)功能造成意外行為

冪等性(Idempotent)

無論發送多少次相同的 GET 請求,伺服器狀態都不會改變:

GET /api/users/123  → { id: 123, name: "John" }
GET /api/users/123  → { id: 123, name: "John" }  // 結果相同
GET /api/users/123  → { id: 123, name: "John" }  // 伺服器沒變

可快取(Cacheable)

GET 請求的回應預設是可快取的

http
GET /api/articles/42 HTTP/1.1
Host: example.com

HTTP/1.1 200 OK
Cache-Control: max-age=3600
ETag: "abc123"

{...}

瀏覽器、CDN、代理伺服器都可以快取 GET 回應。

2.3 GET 請求的結構

http
GET /api/users?role=admin&page=1 HTTP/1.1
Host: api.example.com
Accept: application/json
Authorization: Bearer eyJhbGc...

特點

  • 參數放在 URL 的 Query String 中
  • 沒有 Request Body(規範允許但不建議)
  • URL 長度有限制(約 2048 字元,視瀏覽器而定)

2.4 GET 的限制

項目說明
URL 長度約 2000-8000 字元(視平台而定)
資料類型僅能傳送文字(需 URL 編碼)
隱私性參數暴露在 URL 中,可能被記錄
快取風險敏感資訊可能被快取

三、 POST 方法深入解析

3.1 規範定義

根據 RFC 9110:

POST 方法請求目標資源根據資源自身的語義,處理請求中包含的表示

簡單來說:POST 是「給你這些資料,請你處理」。

3.2 POST 的特性

非安全性(Unsafe)

POST 可以產生副作用,這是被允許且預期的:

✅ 正確用法:
POST /api/users          → 創建新用戶
POST /api/orders         → 創建訂單
POST /api/files/upload   → 上傳檔案
POST /api/comments       → 發表評論

非冪等性(Non-Idempotent)

多次執行相同的 POST 請求,可能產生不同結果:

POST /api/orders  → 創建訂單 #1001
POST /api/orders  → 創建訂單 #1002  // 又創建了一個!
POST /api/orders  → 創建訂單 #1003  // 再創建一個!

CAUTION

這就是為什麼瀏覽器在重新整理 POST 頁面時會警告「確定要重新提交表單嗎?」

預設不快取

POST 回應預設不會被快取,除非明確設置:

http
HTTP/1.1 200 OK
Cache-Control: no-store  // 通常會這樣設置

3.3 POST 請求的結構

http
POST /api/users HTTP/1.1
Host: api.example.com
Content-Type: application/json
Content-Length: 58

{
  "name": "John Doe",
  "email": "john@example.com"
}

特點

  • 資料放在 Request Body 中
  • 必須指定 Content-Type
  • 理論上無大小限制(受伺服器配置影響)

3.4 常見的 Content-Type

Content-Type用途範例
application/jsonJSON 格式(最常用){"name": "John"}
application/x-www-form-urlencoded表單預設格式name=John&email=...
multipart/form-data檔案上傳含有邊界分隔的多部分
text/plain純文字Hello World

四、 GET vs POST 核心差異

4.1 比較總覽

面向GETPOST
語意獲取資源處理資料
資料位置URL Query StringRequest Body
安全性安全(不改變狀態)不安全(可能改變狀態)
冪等性冪等不冪等
快取預設可快取預設不快取
書籤可加入書籤無法加入書籤
歷史記錄會保留在瀏覽器歷史不會保留完整資訊
資料長度受 URL 長度限制無限制(受伺服器設定)
資料型別僅文字任何型別
瀏覽器後退無副作用會提示重新提交

4.2 視覺化比較

4.3 安全性常見誤解

> **「POST 比 GET 安全」是錯誤的觀念!**

兩者在傳輸層面的安全性完全相同

誤解事實
POST 資料被加密❌ HTTP 本身不加密,要靠 HTTPS
GET 參數會被看到⚠️ HTTPS 下 URL 也被加密(但可能被記錄)
POST 更難被攔截❌ 用抓包工具一樣能看到 Body

真正的差異在於

  • GET 參數會出現在瀏覽器歷史、書籤、伺服器日誌
  • POST Body 通常不會被這些地方記錄

五、 實戰情境分析

5.1 情境:搜尋功能

應該用 GET

http
GET /api/products?keyword=laptop&category=electronics&sort=price

原因:

  • 搜尋不會改變伺服器狀態 → 安全
  • 結果可以被快取
  • URL 可分享、可加入書籤
  • 瀏覽器後退不會有問題

5.2 情境:登入

應該用 POST

http
POST /api/auth/login HTTP/1.1
Content-Type: application/json

{
  "email": "user@example.com",
  "password": "secret123"
}

原因:

  • 密碼不應出現在 URL 中
  • 登入狀態會改變(建立 Session)
  • 不應被快取
  • 不應被重放

5.3 情境:分頁 API

應該用 GET

http
GET /api/articles?page=2&limit=10

原因:

  • 只是查詢,不改變狀態
  • 可分享特定頁面連結
  • CDN 可快取各頁面

5.4 情境:表單提交

應該用 POST

http
POST /api/contact HTTP/1.1
Content-Type: application/x-www-form-urlencoded

name=John&email=john@example.com&message=Hello

原因:

  • 會創建新的聯絡紀錄
  • 資料量可能較大
  • 不應被重複提交

六、 POST-Redirect-GET 模式

為了避免使用者重新整理後重複提交表單,常用 PRG 模式:

實作程式碼

javascript
// Express 後端
app.post("/api/orders", async (req, res) => {
  const order = await createOrder(req.body);
  res.redirect(303, `/orders/${order.id}`);
});

總結

問題答案
何時用 GET?獲取資料、搜尋、分頁、可分享的連結
何時用 POST?創建資源、登入、表單提交、檔案上傳
GET 限制?URL 長度、僅純文字、參數暴露
POST 風險?非冪等,可能重複提交

> **簡單判斷法**:問自己「這個操作會改變伺服器上的資料嗎?」

  • 不會 → GET
  • 會 → POST(或其他適當的方法)

進階挑戰

  1. 使用瀏覽器開發者工具,觀察一個 GET 請求和一個 POST 請求的差異(Headers、Payload、Timing)。
  2. 嘗試設計一個 API:用戶可以「按讚」一篇文章,你會用 GET 還是 POST?為什麼?如果要求冪等(按第二次取消讚),又該怎麼設計?
  3. 實作一個 PRG 模式的表單提交流程。

延伸閱讀與資源