簡短來說:GET 應該仍然是你在 Laravel 中的預設搜尋方法,POST 仍然是複雜篩選的務實備案,而 QUERY 只有在你足夠重視 HTTP 語義以至於願意承擔基礎架構成本時,才值得採用。這才是真正的取捨。
新的 HTTP QUERY 方法不再只是標準討論中的想法。它已於 2026 年 6 月 成為 RFC 10008。它的理念很清楚:讓客戶端傳送一個安全、等冪且帶有主體的請求。換句話說,保留檢索的語義,同時避免將大型搜尋酬載塞進查詢字串,或是把安全的讀取偽裝成 POST 的醜陋作法。
這聽起來非常適合搜尋 API。Laravel 團隊,尤其是那些在建置管理面板、報表端點、AI 輔助篩選或多條件儀表板的團隊,會認為:終於有一個方法能符合實際意圖了。
問題在於,協定正確性只是工作的一半。另一半則是周遭的一切:代理、客戶端、快取、API 閘道、分析工具、團隊熟悉度、瀏覽器行為,以及備援設計。QUERY 絕對可以讓 API 更乾淨,但也可能成為那些技術上優雅、卻悄悄增加未來兩年維護負擔的選擇之一。
QUERY 解決了 GET 和 POST 無法解決的問題
當你的搜尋端點已經超出一個簡潔的 URL 時,QUERY 的價值最容易看出來。
簡單的篩選適合放在 GET:
GET /orders?status=paid&sort=-created_at&page=2
Enter fullscreen mode Exit fullscreen mode
當篩選條件小、可連結且適合快取時,這仍然是最佳選擇。Laravel、瀏覽器、CDN、可觀測性工具,以及全球每一個 API 客戶端都懂這個做法。
問題出在搜尋酬載變得更豐富時:
- 巢狀篩選
- 分組條件
- 長串 ID 清單
- 帶有權重的全文搜尋規則
- 日期區間與分面
- 匯出式報表查詢
- AI 生成的篩選酬載
此時,團隊通常會轉向使用 POST /orders/search 搭配 JSON。這可行,但會混淆語義。你把一個唯讀操作弄得像狀態改變的寫入。RFC 10008 正是為了解決這個差距而存在。它將 QUERY 定義為安全且等冪,類似 GET,同時仍允許在主體中傳送請求內容。RFC 明確將其描述為 URI 型 GET 查詢與主體型 POST 查詢之間的橋樑。
這種語義清晰度並非學術問題。它會影響重試邏輯、快取假設、API 可讀性,以及未來維護者對你端點的理解方式。一個 POST 搜尋路由總是強迫你加上心理註記:「是的,這其實是讀取。」而 QUERY 路由則不需要。
RFC 中另一個不錯的細節是:可以使用標準的 Allow 標頭,以及新的 Accept-Query 回應標頭來發現支援情況,後者可以廣告支援的查詢主體媒體類型。在規格上,這比「在這裡用 JSON POST,相信我們」這種未記載的慣例更乾淨。
因此,如果純粹從語義正確性來比較方法,排名很簡單:
-
GET適合小型、URL 友善的搜尋。 -
QUERY適合複雜、基於主體但仍是安全讀取的搜尋。 -
POST是相容性的主力,而不是最乾淨的模型。
這是好的部分。更困難的問題是,你的實際堆疊是否能接受它。
QUERY 在 Laravel 程式碼庫中真正有幫助的地方
如果你要採用 QUERY,請針對語義增益確實存在而非表面化的端點來做。
最佳適用:複雜的安全搜尋
最佳案例是一個搜尋或報表端點,其酬載太大或結構太複雜,無法放在查詢字串中,但同時沒有副作用。
想像一個內部分析畫面,帶有巢狀篩選群組:
{
"filters": [
{"field": "status", "operator": "in", "value": ["paid", "refunded"]},
{"field": "country", "operator": "eq", "value": "IN"}
],
"date_range": {
"from": "2026-07-01", "to": "2026-07-27"
},
"sort": [
{"field": "revenue", "direction": "desc"}
],
"page": 1, "per_page": 50
}
Enter fullscreen mode Exit fullscreen mode
這個酬載放在 GET 會很尷尬,但它明顯不是寫入。QUERY 比 POST 更符合意圖。
更適合共享搜尋引擎
如果你的 Laravel 應用程式對外公開一個被多個客戶端使用的搜尋抽象層,QUERY 也可以讓合約更清楚。行動應用程式、內部工具、後端服務和 AI 代理,都會理解這是在查詢資源,而不是變更資源。
當你的 API 表面開始擴張時,這點就很重要。把每個安全搜尋路由都命名為 .../search 並放在 POST 後面雖然可行,但會慢慢讓你的程式碼庫養成習慣:只要篩選條件變得不方便,就把讀取當成寫入。
更乾淨的服務邊界
這裡好的 Laravel 設計不是「把搜尋邏輯放在路由中,然後慶祝現代 HTTP」。好的設計是將所有搜尋輸入正規化為單一查詢物件,讓傳輸成為邊緣考量。
例如:
final class OrderSearchData
{
public function __construct(
public array $filters = [],
public array $sort = [],
public ?string $from = null,
public ?string $to = null,
public int $page = 1,
public int $perPage = 50,
) {}
public static function fromRequest(Request $request): self
{
$payload = $request->isMethod('QUERY')
? $request->json()->all()
: $request->all();
return new self(
filters: $payload['filters'] ?? [],
sort: $payload['sort'] ?? [],
from: data_get($payload, 'date_range.from'),
to: data_get($payload, 'date_range.to'),
page: (int) ($payload['page'] ?? 1),
perPage: min((int) ($payload['per_page'] ?? 50), 200),
);
}
}
Enter fullscreen mode Exit fullscreen mode
這個模式很重要,因為如果你採用 QUERY,你幾乎肯定也要保留 GET 或 POST 的相容路徑。應用程式核心不應該在意搜尋酬載是透過哪種傳輸方式帶進來的。
為什麼 QUERY 仍然可能成為維護陷阱
這是人們在對標準感到興奮時會跳過的部分。
QUERY 在基於主體的讀取上,比 POST 更符合語義。這不代表它對 2026 年的每個 Laravel 團隊來說,都是更好的營運選擇。
Laravel 很友善,其餘堆疊可能不是
Laravel 的請求物件很彈性。文件明確說明 Request::method() 會回傳傳入的動詞,而 isMethod() 可以測試它,這表示框架可以檢查到達它的任何方法。Laravel 路由文件也只顯示常見動詞加上 match() 和 any() 的一級輔助函式。這個差距很說明問題。
QUERY 目前還不是 Laravel 的一級快樂路徑。你正在離開鋪好的道路。
這表示你必須思考框架程式碼之外的事:
- 你的網頁伺服器會原封不動地傳遞這個方法嗎?
- 你的負載平衡器或 API 閘道會允許它嗎?
- 你的 WAF 規則會預設將它視為可疑嗎?
- 你的請求記錄、儀表板和 APM 工具會正確地將它歸類嗎?
- 你的 SDK、測試工具和生成的客戶端會保留它嗎?
一個方法可以是有效的 HTTP,卻在真實基礎架構中多年都顯得笨拙。
瀏覽器和客戶端人體工學仍然不均勻
這是許多優雅 API 想法失去動能的地方。你的伺服器可能接受 QUERY,但你的使用者不只是伺服器。他們是瀏覽器、前端應用程式、行動客戶端、Postman 集合、CLI 工具、生成的 SDK,以及內部腳本。
即使客戶端技術上可以傳送自訂方法,也不代表周遭工具會把它視為正常。團隊最終會發現軟性失敗,而不是硬性失敗:中介軟體假設、CORS 摩擦、分析盲點、自動生成的說明文件錯誤呈現方法,或是測試工具需要手動覆寫。
一個規格乾淨但工具採用度尷尬,正是維護陷阱誕生的方式。
快取在理論上比在一般基礎架構中更好
RFC 10008 表示 QUERY 的回應可以快取。這比通常含糊的 POST 搜尋模式,在語義上確實有優勢。但同一份 RFC 也指出,快取 QUERY 本質上比 GET 更複雜,因為快取金鑰必須考慮請求主體。
這就是關鍵的實務重點。一般快取和 CDN 是圍繞 GET 的肌肉記憶建立的。一旦你的快取金鑰依賴請求內容,你就需要對中介程式的行為有更多信心。
所以是的,QUERY 在語義上比 POST 更適合快取。不,這並不代表你的堆疊會突然提供 effortless 的查詢主體快取。
可觀測性在變好之前會先變得稍差
GET 請求很容易檢查,因為篩選條件在 URL 中。這很吵,但營運上很方便。POST 請求很無聊但很熟悉。QUERY 處於一個尷尬的中間狀態:像 GET 一樣安全,像 POST 一樣基於主體,而且不常見到某些工具預設不知道該怎麼處理它。
如果你的團隊非常依賴請求記錄、指標標記或運維儀表板,不常見的動詞會產生額外工作。不是不可能的工作。只是你在宣稱設計「更乾淨」之前,需要預算的工作。
合理的 Laravel 實作模式
如果你想實驗 QUERY,請用雙路徑設計來做,而不是純粹主義的作法。
錯誤的推出方式是:
- 發明一個
QUERY端點 - 立即移除
POST搜尋 - 假設基礎架構會配合
- 一次一個代理或一個客戶端地發現問題
更好的推出方式是集中搜尋邏輯,並有意識地公開多種傳輸方式。
建議的路由形狀
將你的標準搜尋行為保留在一個動作或服務中,然後公開:
-
GET用於簡單篩選 -
POST作為廣泛相容性路由 -
QUERY作為有能力的客戶端的語義正確路由
看起來可以像這樣:
use App\Http\Controllers\OrderSearchController;
use Illuminate\Support\Facades\Route;
Route::get('/orders', [OrderSearchController::class, 'index']);
Route::post('/orders/search', [OrderSearchController::class, 'search']);
Route::any('/orders/query', [OrderSearchController::class, 'query']);
Enter fullscreen mode Exit fullscreen mode
而在控制器中:
final class OrderSearchController
{
public function index(Request $request, OrderSearch $search)
{
$data = OrderSearchData::fromRequest($request);
return response()->json($search->run($data));
}
public function search(Request $request, OrderSearch $search)
{
$data = OrderSearchData::fromRequest($request);
return response()->json($search->run($data));
}
public function query(Request $request, OrderSearch $search)
{
abort_unless($request->isMethod('QUERY'), 405);
$data = OrderSearchData::fromRequest($request);
return response()
->json($search->run($data))
->header('Accept-Query', 'application/json');
}
}
Enter fullscreen mode Exit fullscreen mode
這在框架純粹主義的角度看起來不太漂亮,但很誠實。它承認 Laravel 目前還沒有提供精緻的 Route::query() 抽象,而相容性仍然很重要。
驗證和等冪性仍然很重要
因為 QUERY 是安全且等冪的,你的實作需要表現得像它一樣。這聽起來很明顯,但很容易意外違反。
不要讓一個使用 QUERY 的搜尋端點:
- 將「上次搜尋」狀態作為副作用保存
- 在每次請求時寫入稽核資料列,除非你願意將它們視為良性副作用
- 自動觸發匯出、通知或佇列工作
- 以類似寫入 API 的方式預熱昂貴的實體化檢視
如果你將端點標記為 QUERY,請保持它在營運上是唯讀的。否則你會得到兩者最壞的情況:不熟悉的方法加上破壞的語義。
如果你認真,就使用 Accept-Query
如果你採用 QUERY,不要把它藏成部落知識。RFC 10008 新增 Accept-Query 回應標頭是有原因的。如果你的端點支援 JSON 查詢主體,就廣告它。
這會讓功能可被發現,並讓你的 API 合約比隨機的內部 wiki 頁面更誠實一些。
那麼 Laravel 團隊應該使用 QUERY 嗎?
通常,不要作為唯一的搜尋方法。
這是我在真正的程式碼審查中會捍衛的建議。
如果你的受眾廣泛、公開、以瀏覽器為主,或是大量整合,GET 加上 POST 仍然是最安全的組合。GET 涵蓋簡單且 URL 友善的案例。POST 涵蓋複雜的基於主體的搜尋,而不需要強迫堆疊的其餘部分學習一個仍然不常見的動詞。
如果你的環境受控、客戶端已知、基礎架構團隊可以驗證方法傳遞,而且你足夠重視協定語義以至於能妥善維護邊緣,那麼 QUERY 就值得考慮。在這個較狹窄的設定中,它確實比把每個複雜讀取都假裝成 POST 更乾淨。
所以真正的比較看起來像這樣:
-
使用
GET,當搜尋自然地可以用 URL 表示,且受益於通用工具支援時。 -
使用
POST,當相容性比語義純粹性更重要時。 -
使用
QUERY,當操作確實是安全讀取、酬載屬於主體,且你的堆疊已經成熟到足以支援較少使用的方而不出意外時。
最後一個條件就是整個故事。QUERY 不是噱頭,也不是自動的陷阱。它是一個更銳利的工具,只有當系統的其餘部分準備好時才會有回報。
如果你的團隊仍在為基本的 API 一致性而奮鬥,就不要從這裡開始。如果你們已經關心傳輸語義、快取行為和多客戶端搜尋設計,那麼 QUERY 終於是一個真正的選項。只是要像基礎架構決策一樣採用它,而不是語法升級。
在 QCode 上閱讀完整文章:https://qcode.in/http-query-laravel-cleaner-search-api-future-maintenance-trap/
0 Comments
Log in to join the conversation.No comments yet. Be the first to share your thoughts.