配列をPOSTするとき、jQueryだと以下のように書けます。
$.post('http://example.com', {
ids: [1,2,3]
})
このとき、以下のようなリクエストが送信されます。
注目してほしいのはContent-TypeとForm Dataです。Content-Typeは application/x-www-form-urlencoded
なので、Form送信時に使用されるContent-Typeで、FormDataが送られています。 key[]=value
形式の配列はサーバサイドでは [1,2,3]
のような配列にパースされます。
同じ物をFetch APIを使って、書いてみます。fetchでFormのように送信したい場合、bodyにFormDataオブジェクトをセットすればOKです。したがって、以下のように書けば動きそう…ですが、このコードは↑と同じようには動きません。
const data = new FormData();
data.append('ids', [1,2,3]);
fetch('http://example.com', {
method: 'POST',
body: data,
mode: 'no-cors',
})
このとき送信されるリクエストは以下のような形になります。
Content-Typeはマルチパートになっていますが、フォームとして送信できているので問題ありません。問題はForm Dataで、キーは ids
、値には [1,2,3]
を toString()
したものが入っています。これはこれで、サーバサイドのプログラムでカンマ区切りをsplitしてもよいのですが、既存APIが key[]=value
方式を受け付けるようになっていると、このままでは上手くいきません。
多少トリッキーですが、値が配列である場合にkeyをいじる処理を追加することで、fetch + FormDataで key[]=value
方式のデータを送信できます。
function createFormData(data) {
const form = new FormData();
Object.keys(data).forEach(key => {
const value = data[key];
if (Array.isArray(value)) {
value.forEach(entry => {
form.append(key + '[]', entry);
});
} else {
form.append(key, value);
}
});
return form;
}
fetch('http://example.com', {
method: 'POST',
mode: 'no-cors',
body: createFormData({ ids: [1,2,3] }),
});