
HTTP QUERY 是什麼?2026 年 6 月,IETF(Internet Engineering Task Force, 網際網路工程任務組)正式發布 RFC 10008《The HTTP QUERY Method》,在 HTTP Semantics(語意) 裡多了一個新 Method(方法):QUERY。我們每天上網用的 HTTP, DNS, TCP/IP 等底層協定就是 IETF 制訂出來的,這次多了一個專門給「複雜唯讀查詢」用的方法。
Backend Engineer(後端工程師)開發 API、或是大型電商後台做過「條件很多、篩選很複雜」的查詢,大概都踩過這個坑:GET 塞不進 URL,POST 的 Semantics 又不像在讀資料。那就用 POST /search 假裝在讀資料,這作法應該是每個後端 RD 都曾做過的事 XD;時至今日協定層終於給了一個正規解法囉~
這篇會講清楚:RFC 10008 / HTTP QUERY 是什麼、和 GET, POST 差在哪、實務上可以怎麼使用以及 PM 為什麼值得花時間理解(若覺得內容太長,那文末有 TL;DR 版本 與 詞彙對照)。
一句話來搞懂它: QUERY 就像「帶 request body(請求本文) 的唯讀查詢」, 較 Safe(安全)、可重試、可 Cache(快取),不用再拿 POST 假裝只是在讀資料。
RFC 10008 是 IETF HTTP 工作小組在 2026 年 6 月發布的 Proposed Standard(建議標準),作者包含 Julian Reschke(greenbytes), James M. Snell(Cloudflare), Mike Bishop(Akamai)。IANA 已將 QUERY 登記為 Safe(安全) 且 Idempotent(冪等) 的 HTTP 查詢方法。
規格定義很直白:
Client(客戶端) 用 QUERY Request(請求) 目標資源,以 Safe(安全) 且 Idempotent(冪等) 的方式處理 request body(請求本文) 裡的內容,並把處理結果放在 Response(回應) 裡。Semantics(語意) 上接近 POST「可以帶 body」,但 QUERY 可以自動重試,不必擔心重送造成狀態被改一半。
和既有方法的關係,可以參考以下的整理:
| 屬性 | GET | QUERY | POST |
|---|---|---|---|
| 安全(不改變目標資源狀態) | 是 | 是 | 不保證 |
| 冪等(可安全重試) | 是 | 是 | 不保證 |
| 可快取 | 是 | 是 | 僅限特定 POST 快取情境 |
| Request Body | 無定義語意 | 預期有 body,body 本身就是查詢 | 預期有 body |
| 查詢條件放哪 | URL 查詢字串 | Request Body | Request Body |
規格還定義了幾個配套機制,這在 PM 和 RD 協作時會用到(溝通起來比較沒有隔閡):
Content-Type 必填:Server(伺服器) 若缺漏或與內容不一致,必須回 4xx。Accept-Query Response Header(回應標頭):Server 可宣告支援哪些查詢格式(例如 application/json, application/sql)。Client 也可先送 OPTIONS 或 HEAD 試試看支不支援。Content-Location / Location:可把「查詢結果」或「查詢本身」綁成 URI(Uniform Resource Identifier,統一資源識別碼),之後用 GET 重取,不必再送一次 body。這個標準其實經歷很長的路:最早可追溯到 2015 年的 individual draft,曾叫 SEARCH,2021 年改名 QUERY 來脫離 WebDAV 的包袱,2025 年 11 月 IESG 核准,2026 年 6 月正式成為 RFC 10008(標準化過程與文件狀態可在 IETF Datatracker 的 RFC 10008 頁 查看)。HTTP 通常 (根本) 不會異動,一變動絕對是大事,所以我認為除了 RD 以外常常協作的 PM 也值得認真看看。
過去要向 Server 做複雜搜尋或篩選,實務上 RD 通常只有兩條路:
| 做法 | 怎麼送 | 問題 |
|---|---|---|
| GET | 參數全塞進 URL 查詢字串 | 常卡在 2 ~ 8 KB 就爆(Proxy, CDN、瀏覽器各自不同) PII(個資)還會留在網址,進瀏覽器歷史與 access log |
| POST | 複雜條件放 request body | Semantics 像「可能要寫入」,不是唯讀、也不是 Idempotent 斷線不敢自動重試,共享 Cache 也不當成讀取 |
RFC 10008 列出了四個「把查詢塞進 URL」會遇到的問題:長度(實務常見約 2 ~ 8 KB 就爆,RFC 9110 只保下限 8,000 bytes)、編碼(結構化資料硬塞 URI 很浪費)、隱私(URL 比 body 更容易進 access log、書籤、Referer)、Semantics(每種參數組合都像不同資源,Cache 與監控指標被切碎)。
過去的 Workaround(變通做法、臨時方案)是 POST /search。能查,但 Semantics 告訴 HTTP:「這可能會改狀態。」結果是:
QUERY 把三件事放在一起:帶 body、唯讀 Semantics、可 Cache 可重試。
HTTP 從來沒禁止 GET 帶 body 啊?技術上沒錯,但這條路不是正當的解法。
| 說法 | 實際狀況 |
|---|---|
| 「規範禁止 GET 帶 body」 | 不對。RFC 9110 說的是 GET 的 body 沒有通用 Semantics;有些實作會直接拒絕,也有 request smuggling(請求偽造) 的疑慮。 |
| 「GET 帶 body 可以當企業級解法」 | 不建議。部分雲端 WAF(例如 AWS WAF)會擋帶 body 的 GET,而且關不掉這項檢查。 |
| 「所以大家才用 POST /search」 | 對,但是用錯方法湊合。 |
| 「QUERY 是多此一舉嗎?」 | 不是。它是給「帶 body 的唯讀查詢」一個標準名字與 Semantics,不是發明 JSON 傳輸。 |
也就是說:過去確實有「GET 帶 body」這種 Workaround,也有「POST 假裝查詢」;現在多了 QUERY,是第三條正規路,而不是取代所有 GET。
另一個常見誤解是:「用 JSON 傳資料不是早就有了嗎?」POST 早就用 JSON 了。QUERY 補的不是傳輸格式,而是 HTTP Method Semantics:Safe, Idempotent, Cacheable,讓 Intermediary(中間層) 知道「這是在問問題,不是在寫資料」。
Server 用 Accept-Query 告訴 Client 支援哪些查詢格式,例如:
Accept-Query: application/json, application/sql
Client 送錯時,RFC 10008 建議用不同狀態碼區分「格式不對」與「內容不對」:
| HTTP Status Code | 白話解釋 | 例子 |
|---|---|---|
| 415 Unsupported Media Type | Server 不認識這種查詢格式 | 只收 application/json,你送 application/sql |
| 422 Unprocessable Content | 格式看得懂,但查詢內容有誤 | JSON 合法,但 filter.status 欄位不存在 |
| 400 Bad Request | Content-Type 缺漏,或與 body 不一致 | 宣稱 JSON 卻送純文字 |
BTW 在 PM 寫 PRD 或驗收時,可以直接要求 API 文件標明這三種情境的回應,減少「直接回 4xx」這種模糊地帶的說法。
QUERY /api/work-orders/search HTTP/1.1
Host: mes.example.com
Content-Type: application/json
Accept: application/json
{
"filters": {
"status": ["Released"、"InProcess"],
"line": "A-吊飾線",
"due_before": "2026-07-15"
},
"sort": [{"field": "priority"、"dir": "desc"}],
"page": {"size": 50、"cursor": null}
}
(Released, InProcess 是 API 的欄位值,也就是生管口語的「已核准」「進行中」通常對應這兩種狀態。)
Server 若支援,可在 Response 裡附:
Accept-Query: "application/json"
讓 Client 知道這個路徑接受什麼查詢格式。
上一節只能看靜態 HTTP 內資訊;這裡我寫簡單兩個範例來做對照,篩選條件用上述提到的同一份 JSON 資料(A 吊飾線、已核准與進行中、交期早於 7/15),也就是後面生管 Kevin 早會看板會下的那種查詢。兩個 Demo 只差在 Method(方法):一個還在用 POST 假裝查詢,一個改成 QUERY。
畫面上那三個備註標籤,這裡白話說明一下:
| 標籤 | 白話 |
|---|---|
| Safe(安全唯讀) | 這次操作不應該改系統的狀態,因為只是在問,不是在寫資料 |
| Idempotent(冪等) | Wi‑Fi 不穩、多按幾次「重試」,結果跟按一次一樣 |
| Cacheable(可快取) | 相同條件短時間可重新使用上次的結果,不用一直打後端 |
因為這裡沒接真實的 MES API 資料:跨域麻煩,而且現場還沒幾套 Server 認 QUERY。Request / Response 都是在瀏覽器模擬的;請看上面三個標籤,以及按 「模擬斷線後重試」 之後黃色便條紙的提示怎麼寫。
過去:POST /search(假裝查詢)
先按「送出」,看標籤「不保證」、「不適合」;再按「模擬斷線後重試」,讀黃色便條紙的提示。POST 不保證冪等,Proxy 可能不敢幫你重送;若沒有跟後端溝通清楚,那 MES 系統有機會被計算成重複報工。這就是前面說 POST /search 能查,但整條請求路徑卻誤當成在寫資料的原因。
現在:HTTP QUERY(唯讀查詢)
同一包 body,換 QUERY 再試:先送出,標籤應變成三個「是」;再按重試,第二次 body 沒改會看到 cache: "HIT"(快取鍵含 body,不是只看網址)。後面生管 Kevin 看板 Wi‑Fi 不穩多按重新整理、品保儀表板短暫 Cache,講的就是這套;能不能真的快取,還得看 Gateway 支不支援、權限怎麼切分。
所以 PM 在測試驗收時要確認的不是「搜尋能不能查」,而是「斷線能不能重試、相同條件能不能快取、API 文件寫的是讀還是寫」。
這裡我就用 MES 工單作為範例說明。
要判斷用 GET 還是 QUERY,先看你有沒有確定的工單號。
一個相對務實的分工會是這樣:GET 留給「已知 ID 的單筆資源」;QUERY 留給「條件很多的搜尋與篩選」。例如 MES 系統可以用 GET /api/work-orders/WO-01 拿單張工單,用
QUERY /work-orders/search 做複雜列表;至於舊的 POST /search 就繼續沿用,
新功能再換成 QUERY 就好(尤其針對很多政府標案、金融類的產品,最怕的就是改 A 壞 B 這種狀況,對 RD 真的多一事不如少一事,千萬別去盧小工程部門 XDD)。
| 情境 | 建議方法 | 原因 |
|---|---|---|
| 單筆資源、已知 ID | GET | Semantics 最清楚(GET /api/work-orders/WO-01) |
| 簡單列表、參數少 | GET | URL 夠用,生態系也最熟 |
| 複雜唯讀查詢、篩選 JSON 很大 | QUERY | 靠 body 承載,而且是 Safe, Idempotent, Cacheable |
| 建立、更新、刪除、下單、報工 | POST / PUT / PATCH / DELETE | 會改狀態,不該用 QUERY |
| GraphQL 唯讀 query | QUERY(理想上) | 過去被迫用 POST,是因為 Semantics 不符合 |
以皮克敏娃娃玩具廠的範例來說明(有興趣可以看看生管為什麼一直問工單?訂單 vs 工單差在哪?),這裡我以兩個可能最常碰到的情境來說明「若新模組或新看板要上 QUERY,會長什麼樣」。
早會前生管 Kevin 盯著工單看板,要撈「A 吊飾線、已核准、本週要交、跟紅葉有關、優先序高」工單資訊,那一批不是點開 WO-01 單張(那用 GET /api/work-orders/WO-01 就好)。七、八個條件硬塞 URL 動輒幾千個字元,各層 Proxy 還可能截斷;RD 當初只好做成 POST /api/work-orders/search,語意卻像在下指令。
若這支 API 改成 QUERY /api/work-orders/search,篩選、排序、分頁全放 body,Kevin 比較有感的是:廠內 Wi‑Fi 不穩時,重新整理看板多按一次,不用再猜「剛剛到底有沒有查到」。看板是製造廠內 Web(打內網 API),不是對外跨;上線前仍要實測 Gateway 是否認 QUERY(參考下面實務採用建議)。早會前十個人開同一頁,Gateway 在權限邊界內可短 TTL(Time-to-Live, 快取存留時間) Cache 的話,也不會把 MES 打到卡住;篩選條件也不會整串印在 access log 裡。
上週 A 線「治具未到」在現場鬧了兩天,品保要寫 8D Report(八大步驟問題解決報告),也就是工廠處理品質異常、客訴時常用的結構化改善報告,這時得先把異常工單撈齊:哪幾張、卡在哪一站、原因代號怎麼分、嚴重度怎麼排。條件裡 AND / OR 混在一起,用 GET 會變成一條沒人想維護的查詢字串;但改用 POST,防火牆和監控又會誤以為有人在寫入資料。
若改送 QUERY /api/exceptions/search,時間區間、原因代號、產線、結案與否都寫在 body。主管重新整理異常儀表板,相同條件在內網、依角色授權的前提下,可以 Cache 三十秒到一分鐘。若要再往下撈(料號 PKM-RED-001、途程 v3、製程 20 到 30 之間出現過某治具的工單),巢狀更深,一樣塞 body 比硬是用 URL 還合理。報告裡還能貼 Response 回的 Content-Location,下次打開不用重送整包條件。
| 場景 | 典型 API 路徑 | 為何 QUERY 優於 POST / 長 GET |
|---|---|---|
| 工單複合搜尋 | /api/work-orders/search | 條件多、要分頁排序,URL 塞不下 |
| 途程追溯 | /api/traceability/query | 巢狀條件多,Response 可附 Content-Location 快照 |
| 異常事件分析 | /api/exceptions/search | 唯讀分析,適合短時間 Cache、可安全重試 |
| OEE 儀表板 | /api/metrics/oee/query | 讀取密集,適合短 TTL Cache |
| 跨廠在製 | /api/cross-plant/wip-search | body 大,跨 Gateway 時 Semantics 要一致 |
大型電商(年訂單量百萬級以上、SKU(貨號、品號)十萬以上、多倉庫多通路)的後台與前台 API,「搜尋、篩選、分析」佔流量極高比例。2026 年前幾乎清一色 POST /search 或 GraphQL over POST。下面三個場景最常碰到合規與語意混淆,其餘併入下表。
客服後台依「手機末三碼、日期區間、付款狀態、物流狀態、是否含客訴標籤」等條件來查訂單,高峰時每秒數千次。查詢條件含個資,放 URL 會進 access log,合規風險高;走 POST 又難 Cache、難重試。 查詢條件放 body、不進 URL log,相同條件短時間可 Cache(權限邊界見資安章節)。對法務也好說明:查詢條件在 body、操作是安全的唯讀,降低 log 外洩的疑慮。
使用者下單前要算「各倉可售量、運送中庫存、預留量、門市可取貨」,B2C 與 B2B 通路規則還不同。一次查詢常帶數十個 SKU、多倉庫、多通路規則,但 payload 也大;手機 APP 在網路不穩時又需要不斷重試。
QUERY /inventory/availability 批次帶 SKU 列表與通路 context。結帳前的讀取可以安全重試,Client 不必像 POST 那樣擔心「重送會不會多扣庫存」,因為 Semantics 上本來就是讀取。
營運後台要模擬:滿額折、會員折、通路券疊加後,購物車 12 件商品各是多少錢,但還沒真正套用優惠。試算與「套用優惠」必須在語意上分開;過去常用 POST 做試算,工程師容易做錯。
試算走 QUERY(唯讀、可重複執行),真正套用走 POST / PATCH。PM 寫 PRD 時畫界就很清楚:試算是 QUERY,套用是 POST,驗收也比較好核對。
| 場景 | 典型 API 路徑 | 流量特性 | QUERY 帶來的差異 |
|---|---|---|---|
| 目錄多條件篩選 | /catalog/products | 極高 QPS(每秒請求數) | body 承載得住,邊緣有 Cache 空間,Semantics 也對 |
| 個人化推薦 | /recommendations/feed | 高 QPS + 大 body | cache key 可含 body hash,讀取很頻繁 |
| 營運分析 | /analytics/reports/run | 大 payload | 監控上不必再假裝是寫入 |
| B2B 採購查詢 | /b2b/purchase-orders/search | 複雜權限 | 大客戶文件可寫明 安全唯讀 Semantics,方便 Cache 與重試 |
RFC 10008 本身設計合理,但整個生態系有跟沒有上就很難說了,因為風險多半出在「周邊設備還當它是陌生 Method」或「Cache 實作錯誤」。
許多防火牆規則針對 GET / POST / PUT / DELETE 調校。攻擊者對 POST /search 會被 SQL 注入規則擋下,換成 QUERY /search 同一包惡意請求內容卻可能通過。
實務上可以先在 Staging(預發布 / 測試環境) 用同一包惡意內容分別測 POST 與 QUERY,看防火牆反應一不一樣;再更新 Method 的 allowlist(允許清單),讓 QUERY 的 body 接受與 POST 同級檢查(SQL 注入、跨站腳本(XSS)、命令注入)。過渡期也建議把外網 QUERY 流量納入監控,異常時能告警。
如果真的要嘗試的話,可以參考以下的 curl 範例。記得喔!!只能拿來打 staging,不要拿 Production 環境來測。路徑沿用前面的工單搜尋,方便跟前面例子一致;實際請改成你們自己的 staging 網址。這是對照測的方法:用來比較 POST 與 QUERY 的攔截是否一致,不是保證每套 WAF 都會出現這種缺口。
步驟 1:準備同一份「會觸發 SQL 注入規則」的 body
重點只有一個:POST 與 QUERY 用同一包 JSON,只差 Method。 下面 keyword 裡的字串,是常見會被 WAF 特徵規則擋下的寫法,用來確認規則有沒有真的掃到 body;不是要你去搞掛資料庫。
STAGING='https://staging.mes.example.com/api/work-orders/search'
cat > /tmp/waf-payload.json <<'EOF'
{
"filters": {
"keyword": "' OR '1'='1"
},
"page": { "size": 10 }
}
EOF
步驟 2:先用 POST 打一次(對照組)
curl -sS -o /tmp/waf-post.body -w 'POST status=%{http_code}\n' \
-X POST "$STAGING" \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-d @/tmp/waf-payload.json
常見通常會被擋(例如 403),但以你們 WAF 實際回應為準;有的會回自訂狀態碼,或直接把請求丟進應用層。先把「這條路徑對 POST 惡意內容怎麼反應」記下來,後面才有對照基準。
步驟 3:換成 QUERY,body 一字不改再打一次
curl -sS -o /tmp/waf-query.body -w 'QUERY status=%{http_code}\n' \
-X QUERY "$STAGING" \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-d @/tmp/waf-payload.json
步驟 4:把兩邊結果擺在一起看
| 結果 | 代表什麼 | 下一步 |
|---|---|---|
| POST 擋、QUERY 也擋(例如都是 403) | Method 換了,body 檢查仍同級 | 過關;有空再補跨站腳本、命令注入特徵各測一輪 |
| POST 擋、QUERY 放行(200 或進到應用層) | 缺口:規則還只綁在舊 Method | 立刻把 QUERY 寫進允許清單,並讓 QUERY body 套用與 POST 相同規則,再重測 |
| 兩邊都放行 | 這條路徑根本沒在掃 body,或特徵沒吃到 JSON 欄位 | 先把 WAF / Gateway 的 body 檢查修好,再談上 QUERY |
| QUERY 回 405 | 中間層還不認 QUERY | 先處理基礎設施(參考下面「基礎設施不認識 QUERY」);等 Method 通了,再回來做這輪 WAF 對照 |
步驟 5:規則修好後,把步驟 2、3 再跑一次
驗收其實很單純:同一包內容,POST 與 QUERY 的攔截結果要一致。 過渡期也可能在監控上盯「外網 QUERY 被放行、但內容看起來像注入」的流量,避免規則漏了卻沒人發現。
QUERY Response 可 Cache,但 RFC 要求 cache key 必須納入 request body。若 CDN 或廠內 Cache 只 hash URL,攻擊者可能讓其他人拿到錯誤查詢結果。
Cache 層應把 request body 完整雜湊 進 cache key,過渡期寧可保守;若要做 JSON key 排序這類正規化,測試要嚴格。含 PII 的查詢預設不 Cache,或只開 private cache、極短 TTL。
QUERY 標記為 Safe(安全唯讀),傳統 CSRF 中間層可能不檢查。若工程師在 QUERY handler 裡偷偷寫入 side effect(例如更新「最後查詢時間」),可能會留下 CSRF 盲點。
QUERY handler 必須真正唯讀;任何副作用改用 POST。端點只要有狀態變更,不論 Method 名稱都要做 CSRF 保護。HTML form 發不出 QUERY,傳統 forged form 風險低,但 fetch 跨域仍要處理 CORS。
QUERY 不是 CORS safelisted method,跨域 JavaScript 一定會 Preflight OPTIONS。CDN 或 Gateway 若對 OPTIONS 處理不一致,可能出現「以為能查、其實被擋」。
Access-Control-Allow-Methods 要明確列出 QUERY;瀏覽器 fetch 跨域 QUERY 要從頭到尾實測 Preflight。副作用是較難用「看起來像 GET」繞過 CORS body 限制;多數情況這反而是好事。
部分 CDN、反向代理、舊版 Load Balancer(負載平衡器)可能對未知 Method 回 405、剝除 body,或錯誤改寫 Method。越「聰明」的 Intermediary(中間層),越可能用舊規則處理新方法。老舊 Gateway、防火牆能不能認 QUERY,上線前是個謎,不能假設規格出了就全線通。
有人曾用 GET 帶 body 繞過 URL 長度,但 AWS WAF 會直接擋;這也是為什麼需要 QUERY,而不是繼續靠 Workaround。
上線前用 curl 從外網與內網各打一次 QUERY;稽核防火牆 / Gateway 的 method allowlist;Client 過渡期可先 QUERY,收到 405 再 Fallback POST(可參考下面 Client 相容)。內網若還要備援才評估 X-HTTP-Method-Override: QUERY,但實務上其實不太容易。
body 不進 URL log 是優點,但若應用自己把 body 全寫進 log,個資外洩風險仍在。查詢 access log 要遮住敏感欄位,只記 filter 摘要或 hash;客服、訂單查詢類 API 建議做欄位級遮罩。
| 檢查項 | 通過標準 |
|---|---|
| WAF | QUERY body 與 POST 同級檢查 |
| Cache | cache key 含 body hash |
| CSRF | QUERY handler 零副作用 |
| CORS | Allow-Methods 含 QUERY,Preflight 實測要過 |
| Gateway | 外網 QUERY 不能拿掉 body,也不能誤改 method |
| log | body 遮罩,個資不寫明文 |
這不是給工程師看的協定細節而已;它會直接影響 PRD 怎麼寫、API 文件怎麼規範制定、驗收怎麼測試。
過去 PRD 寫「搜尋 API」,RD 可能會預設 POST, QA 問能不能重試、資安問 POST 要不要做 CSRF。其實大家都在糾結同一件事:到底用 GET query 還是 POST query? QUERY 之後,API 文件可以寫明 「唯讀複雜查詢 = QUERY」,不用再吵 Method 到底是哪一個 XD
PRD 與 API 文件可以寫清楚:
減少「明明只是查資料,為什麼不能重試」的返工。
業務說「篩選條件要再加五個維度」時,多半已超出 GET 合理範圍;QUERY 是協定層該走的路,所以不用再叫 RD 硬塞 URL。
| NFR | 沒 QUERY 時 | 有 QUERY 時 |
|---|---|---|
| 重試 | 「Client 自行處理」模糊帶過 | 可要求「QUERY 必須 Idempotent 重試」 |
| Cache | POST Cache 需特例說明 | 可寫「相同 QUERY 可 Cache N 秒」 |
| 合規 | 查詢條件進 URL log | 可要求「查詢條件僅在 body」 |
產品驗收時可要求:
RFC 10008 雖然是正式標準、規格也沒問題,但實務上卻常是「Intermediary(中間層)還沒 準備好,所以應用程式碼再新也沒用」,以下來看看截至 2026 年以來:
| 層級 | 現況 |
|---|---|
| 協定 | RFC 10008 已發布,IANA 也已登記 |
| 瀏覽器 | fetch 可以下 QUERY,但跨域會多一次 OPTIONS,很多 CDN, Proxy 還會擋 |
| Client(非瀏覽器) | curl 可用 -X QUERY;Node.js 22+ 也已能解析 |
| 框架 | Rails, Django, Spring 多還在 PR 階段;ASP.NET 預覽版走得比較前面 |
| CDN / 企業 Proxy | 部分節點不認 QUERY(405、剝 body、誤改 method),也可能直接擋 GET+body |
| 老舊設備 | 舊版 Gateway、廠內代理、嵌入式 client 常回 405 或剝 body |
很多團隊以為「我們 API 已支援 QUERY 就能上線」,但 Request 路徑上還有企業 Proxy, CDN, WAF, Load Balancer。RFC 出了,不等於請求路徑上每一層都認得 QUERY;實務問題常常卡在基礎設施,而不是業務程式碼。
這對 MES 特別真實:廠內 Gateway、舊版介面閘道、客戶 SI 維護的 Reverse Proxy,都可能比你的 MES 核心更晚升級。上線前請從外網與內網各打一次 QUERY,比對回應是否一致。
過渡期 Client 策略可以寫進 PRD:先以 QUERY 送出查詢(body 不變);若收到 405 Method Not Allowed(或你們定義的「不支援 QUERY」訊號),自動改以 POST 重送同一 body(Fallback(備援));兩條路徑的 Response 格式應一致,方便 QA 對照。
要心裡有數:掉進 Fallback POST 時,語意又變回 POST。路徑上的節點不一定敢自動重試、共享 Cache 也不一定當成讀取;Fallback 是「先能查」,不是「已經享有 QUERY 的全部好處」。目標仍是讓 QUERY 在每一層 Intermediary 都通過,逐步減少 Fallback 比例。
這條路徑通常比依賴 X-HTTP-Method-Override: QUERY 更適合當預設相容方案,原因在於:
| 作法 | 好不好做 | 說明 |
|---|---|---|
| QUERY,405 再 Fallback POST | 較好做 | 邏輯在 Client,不靠 Server middleware;邊緣看到的是標準 POST。但 Fallback 這段仍受 POST Semantics 限制,Cache 與重試優勢會打折 |
X-HTTP-Method-Override | 較不好做 | 要 Server 解包,邊緣永遠只見 POST;全程都難發揮 QUERY 的 Cache 與 Semantics 優勢,稽核也不容易一眼看出原本是 QUERY |
也就是說:Override 比較像內網、可控環境的備援;405 Fallback POST 則比較像對外、跨多層基礎設施時較穩的作法。兩者可以並存,但若只能選一個寫進產品規格,多數情境會優先寫前者。
HTTP QUERY 是 RFC 10008(2026 年 6 月)定義的新 HTTP Method:把查詢條件放在 request body,語意上仍是唯讀(Safe)、可重試(Idempotent)、可快取(Cacheable)。白話說,就是「帶 body 的 GET」,專門解決複雜篩選塞不進 URL、又不該假裝成 POST 寫入的問題。
| GET | QUERY | POST | |
|---|---|---|---|
| 查詢條件放哪 | URL | request body | request body |
| 是否安全唯讀 / 冪等 | 是 | 是 | 不保證 |
| 適合場景 | 已知 ID、參數少 | 複雜唯讀搜尋 | 建立、更新、下單等會改狀態 |
POST /search 改成 QUERY?舊的能跑就別急著全改。 新功能、新看板可以優先用 QUERY;上線前一定要實測 Gateway, CDN, WAF 是否認得這個 Method。過渡期可用「先 QUERY,收到 405 再 Fallback POST」。
有,而且多半出在基礎設施還沒跟上,不是協定本身「比較危險」。常見風險包括:中間層誤擋或誤放行、Cache key 沒納入 body 造成串資料、WAF 規則仍只盯 POST。權限、限流、個資不要進 URL,這些原則跟以前一樣要做。
因為它會影響 API 文件、快取策略、重試行為與上線風險。PM 若只寫「做一支搜尋 API」,RD 可能繼續用 POST /search;若規格寫清「複雜唯讀用 QUERY、已知 ID 用 GET」,協作成本與資安討論會清楚很多。
講這麼多,其實就一句話:複雜的唯讀查詢,終於有正式 Method 了,不必再拿 POST /search 假裝在讀資料。
實務上就兩個重點:已知 ID 用 GET,條件一堆才考慮 QUERY;新功能可以試試,舊的 POST /search 能跑就別急著改。Gateway、防火牆認不認 QUERY 這個在上線前一定要不斷地實測。
| 原文 | 中文 | 簡短白話說明 |
|---|---|---|
| HTTP | 超文字傳輸協定 | 瀏覽器、App 跟伺服器說話用的協定;GET / POST / QUERY 都是它的 Method |
| RFC | 請求意見稿 / 標準文件 | Request for Comments:IETF 發布的網際網路標準文件,例如 RFC 10008 |
| IETF | 網際網路工程任務組 | 制訂 HTTP、DNS、TCP/IP 等底層協定的組織 |
| IANA | 網際網路號碼分配局 | 負責登記 HTTP Method 名稱與屬性(例如 QUERY 是 Safe + Idempotent) |
| Proposed Standard | 建議標準 | IETF 標準軌道上的正式階梯之一;RFC 10008 以此狀態發布 |
| API | 應用程式介面 | 系統之間約定好的呼叫方式;這篇多半指 HTTP API |
| URL | 網址 | URI 的一種,常出現在瀏覽器位址列與 access log |
| URI | 統一資源識別碼 | 指到某個資源的識別字串;URL 是 URI 的一種。Content-Location 可能回完整 URL,也可能是 /api/... 這種相對路徑 |
| JSON | JSON | 常用的結構化資料格式;QUERY 的 body 很常是 JSON |
| SQL | SQL | 資料庫查詢語言;也可當 QUERY 的一種查詢格式(看 Server 支不支援) |
| GraphQL | GraphQL | 一種 API 查詢語言;唯讀 query 理想上可用 QUERY,過去常被迫用 POST |
| Client | 客戶端 | 發出 HTTP 請求的那一端(瀏覽器、App, curl, MES 整合程式) |
| Server | 伺服器 | 接收請求、回傳結果的那一端(API, Gateway 後面的應用) |
| Request | 請求 | 從 Client 送到 Server 的一包 HTTP 訊息 |
| request smuggling | 請求偽造 | 前端 Proxy 與後端 Server 對「一個 Request 到哪裡結束」解讀不一致時,攻擊者可能在同一條連線裡夾帶第二個隱藏請求,繞過 WAF(防火牆)或汙染 Cache;GET 帶 body 這類邊界模糊的做法更容易踩到 |
| Response | 回應 | Server 回給 Client 的結果,含狀態碼與 body |
| Method | 方法 | HTTP 動詞(如 GET, POST, QUERY),決定「這是在讀還是在寫」 |
| GET | GET 方法 | 讀取資源;條件通常放 URL,Safe、冪等、可快取 |
| POST | POST 方法 | 可帶 body,但不保證唯讀或冪等;過去常被拿來假裝搜尋 |
| QUERY | QUERY 方法 | RFC 10008 定義的唯讀查詢 Method,帶 body 但不改狀態 |
| OPTIONS | OPTIONS 方法 | 常拿來探路或做 CORS Preflight,問 Server「允不允許 QUERY」 |
| Semantics | 語意 | 這個 Method 在協定上代表什麼意思:讀取、寫入、能不能重試 |
| Safe | 安全唯讀 | 不應改變 Server 上的資源狀態;QUERY 與 GET 都屬 Safe |
| Idempotent | 冪等 | 重送同一請求,效果應與送一次相同;斷線可安全重試 |
| Cache / Cacheable | 快取 / 可快取 | 相同請求可暫存結果,下次不必再打後端 |
| request body | 請求本文 | Request 裡承載資料的主體;QUERY 把查詢條件放這裡 |
| payload | 負載 / 請求內容 | 常跟 body 混著講:這次請求實際帶過去的資料內容 |
| Header | 標頭 | Request / Response 的 metadata,例如 Content-Type, Accept-Query |
| Content-Type | Content-Type 標頭 | 告訴 Server body 是什麼格式;QUERY 缺了或對不上要回 4xx |
| Accept-Query | Accept-Query 標頭 | Server 宣告接受哪些查詢格式(如 JSON, SQL) |
| Content-Location | Content-Location 標頭 | 指向「這次查詢結果」的 URI,之後可用 GET 重取 |
| Location | Location 標頭 | 這裡常指「查詢本身」的 URI,之後用 GET 可重跑查詢 |
| cache key | 快取鍵 | 快取系統辨識「是不是同一個請求」的 key;QUERY 必須含 body |
| TTL | 快取存留時間 | Time-to-Live:這筆快取要留多久;時間一到就失效,下次要重查 |
| hash | 雜湊 | 把 body 算成固定長度指紋,常拿來組 cache key,避免只靠 URL |
| access log | 存取紀錄 | Server / Proxy 記下誰打了哪個網址;條件若放 URL 很容易被記進去 |
| Proxy | 代理伺服器 | 站在 Client 與 Server 之間轉發請求的設備(CDN、企業 Proxy) |
| Reverse Proxy | 反向代理 | 站在 Server 前面收流量、轉發進內網的 Proxy(廠內 Gateway 常見) |
| CDN | 內容傳遞網路 | 把內容放到邊緣節點加速;也可能擋或不認新的 HTTP Method |
| Load Balancer | 負載平衡器 | 把流量分到多台 Server;舊設備可能不認 QUERY |
| Intermediary | 中間層 | 請求路徑上所有轉手節點:Proxy, Gateway, WAF, Load Balancer |
| Gateway | API 閘道 | 統一入口,負責路由、認證、限流、Method 轉發 |
| WAF | 網頁應用程式防火牆 | 在流量進入應用前檢查惡意 payload 的安全設備 |
| allowlist | 允許清單 | 只放行清單上的 Method / 來源;沒寫進 QUERY 就可能被擋 |
| staging | 預發布 / 測試環境 | 上正式站前用來驗證的環境;WAF 對照測請只打這裡 |
| XSS | 跨站腳本 | 把惡意腳本塞進網頁;WAF 常與 SQL 注入一起檢查 |
| CORS | 跨來源資源共用 | 瀏覽器跨網域呼叫 API 的安全規則 |
| Preflight | 預檢請求 | 跨域前先送 OPTIONS 問 Server「QUERY 可不可以」 |
| CSRF | 跨站請求偽造 | 騙瀏覽器代使用者送出非預期請求;傳統防護常只盯 POST 等「會改狀態」的 Method |
| side effect | 副作用 | 查詢過程中偷偷改了狀態(例如更新「最後查詢時間」);QUERY handler 不該有 |
| Fallback | 備援 | 主要路徑失敗時改走備援,例如 QUERY 收到 405 改送 POST |
| X-HTTP-Method-Override | Method Override 標頭 | 外表仍是 POST,用標頭宣稱「其實是 QUERY」;邊緣永遠只見 POST,較難當預設方案 |
| Workaround | 變通作法 | 規格沒寫清楚時的臨時解法,如 POST /search 假裝查詢 |
| PII | 個人可識別資訊 | 姓名、電話等敏感資料;不宜出現在 URL log |
| QPS | 每秒請求數 | Queries Per Second:一秒鐘打進系統多少次請求;數字愈高代表流量愈兇 |
| MES | 製造執行系統 | 管現場工單、進出站、報工的系統;這篇用皮克敏廠當例子 |
| SKU | 貨號 / 品號 | 庫存與商品的最小管理單位;電商一次查詢常帶很多個 |
| OEE | 設備綜合效率 | 產線常用的效率指標;儀表板讀取密集,適合短 TTL Cache |
| 8D Report | 八大步驟問題解決報告 | 品保處理品質異常 / 客訴常用的結構化改善報告 |