URLSearchParamsの重複キー・順序・フォーム形式エンコード
appendとset、重複値の順序、+と空白の違いを例で確認し、サーバーが期待する形式をテストします。
発行・訂正窓口:infostoa · 編集基準
この記事の個別の執筆者・専門査読者の情報は提供されていません。
URLSearchParamsはクエリを単一値のオブジェクトではなく、順序を持つname-valueの組として扱います。filterのように同じkeyを複数送るAPIでは、この違いでリクエストの意味が変わります。WHATWG URL StandardではgetAll()が一致する値をリスト順に返すと定義され、MDN APIガイドは各メソッドの使用例を示しています。
鍵と図形を機械に通して記号が変わる比喩です。順序付きname=valueの組やURLSearchParamsの実際の直列化を示す図ではありません。
重複値を読む・追加する・置き換える
次のqueryにはtagが2つあります。get()は最初の値を返し、getAll()は順番どおりに両方を返します。append()は既存の組を残して末尾に追加し、set()は同名の組を一つの値に置き換えて残りを削除します。
const params = new URLSearchParams("tag=blue&tag=green");
params.get("tag"); // "blue"
params.getAll("tag"); // ["blue", "green"]
params.append("tag", "red");
params.set("tag", "gold"); // tag=goldだけが残る
複数選択filterを維持するならappend()、単一設定値を更新するならset()が使えます。ただし、重複fieldを配列・最初の値・最後の値のどれとして読むかはサーバー側の仕様です。ブラウザーAPIがサーバーの解釈を決めるわけではありません。
+が空白か文字かは入力方法で変わる
文字列constructorにq=a+bを渡すとフォーム形式として解析され、+は空白になり、値はa bです。一方、append("q", "a+b")の+は文字データで、直列化時には%2Bになります。フォーム形式の直列化では空白が+と表されることがあります。元の表記、解析後の値、再直列化したqueryを区別してください。
new URLSearchParams("q=a+b").get("q"); // "a b"
const p = new URLSearchParams();
p.append("q", "a+b");
p.toString(); // "q=a%2Bb"
constructorは完全なURL parserではありません。new URL(location.href).searchParamsやnew URLSearchParams(location.search)のようにquery部分を渡します。
ブラウザーだけでなくAPI境界を試す
ユーザーがtag=blueとtag=greenを選んだ例なら、送信queryに2組が残るか、サーバーが意図した順序の配列として読むか、空文字とkey欠落を区別できるかを統合テストで確かめます。期待が違う場合はAPI契約またはserver parserを調整します。
論理値が同じでも、encodeやURLの直列化後にraw query文字列が異なることがあります。署名・cache key・厳密なlog比較にraw bytesを使うなら、順序、重複、空値、canonical化規則を先に定めてテストしてください。URLSearchParamsはqueryを組み立てるAPIであり、入力のsanitizer、認証、認可ではありません。