タイトル: Javascript のみで form を post で submit する方法
SEOタイトル: JavaScript のみで form を POST 送信する方法完全ガイド
| この記事の要点 |
|
なぜ JavaScript だけで form を作るのか
HTML に を書かず、JavaScript で動的にフォームを組み立てて POST 送信したい場面は意外と多いです。
- ボタンクリックだけで別画面へ POST 遷移させたい(GET だとパラメータが URL に出る)
- SPA から外部サイトに POST で飛ばす(決済ゲートウェイ等)
- 動的に生成したデータをそのまま送信
- ブックマークレット / ユーザースクリプトから送信
最小コード
function postSubmit(url, params) {
const form = document.createElement('form');
form.method = 'POST';
form.action = url;
for (const key in params) {
const input = document.createElement('input');
input.type = 'hidden';
input.name = key;
input.value = params[key];
form.appendChild(input);
}
document.body.appendChild(form);
form.submit();
}
// 利用例
postSubmit('/order/confirm', {
product_id: 123,
qty: 2,
coupon: 'SPRING20'
});
このコードを実行すると、ブラウザは /order/confirm へ POST で画面遷移します。HTML の をクリックしたのと完全に同じ挙動です。
各プロパティの意味
| プロパティ | 値 | 説明 |
|---|---|---|
form.method | POST / GET | HTTP メソッド。デフォルト GET |
form.action | URL | 送信先。相対 / 絶対どちらも可 |
form.target | _self / _blank | 送信結果の表示先。新タブで開きたいときは _blank |
form.enctype | application/x-www-form-urlencoded / multipart/form-data | エンコード形式。ファイル送信は後者必須 |
form.acceptCharset | UTF-8 | 文字コード |
document.body.appendChild は必要か
はい、必要です。DOM ツリーに接続されていない form は submit できません(一部ブラウザで silently fail)。送信後すぐ削除する場合:
document.body.appendChild(form);
form.submit();
// submit() 後にすぐ navigation が始まるので不要だが、
// target=_blank で残したくない場合:
form.remove();
CSRF トークンを含める(Laravel / Rails)
Laravel は をレイアウトに置く慣習があります:
function postWithCsrf(url, params) {
const token = document.querySelector('meta[name="csrf-token"]').content;
const form = document.createElement('form');
form.method = 'POST';
form.action = url;
// Laravel の _token フィールド
const csrfInput = document.createElement('input');
csrfInput.type = 'hidden';
csrfInput.name = '_token';
csrfInput.value = token;
form.appendChild(csrfInput);
for (const key in params) {
const input = document.createElement('input');
input.type = 'hidden';
input.name = key;
input.value = params[key];
form.appendChild(input);
}
document.body.appendChild(form);
form.submit();
}
Rails は authenticity_token という名前、Django は csrfmiddlewaretoken。フレームワークごとに名前が違うので注意。
PUT / DELETE / PATCH を送りたい
HTML 標準の form は GET / POST しか送信できません。Laravel / Rails では _method hidden field を使った method spoofing が定番:
function deleteForm(url) {
const form = document.createElement('form');
form.method = 'POST';
form.action = url;
// Laravel の method spoofing
const methodInput = document.createElement('input');
methodInput.type = 'hidden';
methodInput.name = '_method';
methodInput.value = 'DELETE';
form.appendChild(methodInput);
// CSRF も忘れずに
const token = document.querySelector('meta[name="csrf-token"]').content;
const csrf = document.createElement('input');
csrf.type = 'hidden';
csrf.name = '_token';
csrf.value = token;
form.appendChild(csrf);
document.body.appendChild(form);
form.submit();
}
ファイルを送信したい(FormData)
動的 form はバイナリを直接持てないため、fetch + FormData を使うのが現代的:
async function uploadFile(url, file, extraParams = {}) {
const fd = new FormData();
fd.append('file', file);
for (const k in extraParams) fd.append(k, extraParams[k]);
const token = document.querySelector('meta[name="csrf-token"]').content;
const res = await fetch(url, {
method: 'POST',
headers: { 'X-CSRF-TOKEN': token },
body: fd,
});
return res.json();
}
// 利用例(input[type=file] から取得)
const fileInput = document.querySelector('#file');
fileInput.addEventListener('change', e => {
uploadFile('/upload', e.target.files[0], { user_id: 1 })
.then(json => console.log(json));
});
form.submit() と fetch() の使い分け
| 用途 | form.submit() | fetch() |
|---|---|---|
| ページ遷移 | ○ 起きる | × 起きない |
| サーバ応答を JS で受ける | × | ○ |
| ファイル送信 | ○ (multipart 設定要) | ○ (FormData) |
| クロスオリジン | ○ (リダイレクトは見れる) | ○ (CORS 設定要) |
| 決済ゲートウェイ POST | ○ 推奨 | × CORS で弾かれる |
| SPA 内部 API | × | ○ 推奨 |
配列パラメータの送信
PHP / Laravel は name="tags[]" 形式で配列を受け取ります:
function appendArray(form, name, values) {
values.forEach(v => {
const input = document.createElement('input');
input.type = 'hidden';
input.name = name + '[]'; // tags[]
input.value = v;
form.appendChild(input);
});
}
const form = document.createElement('form');
form.method = 'POST';
form.action = '/search';
appendArray(form, 'tags', ['php', 'laravel', 'vue']);
document.body.appendChild(form);
form.submit();
// → POST /search tags[]=php&tags[]=laravel&tags[]=vue
よくある落とし穴
- form を appendChild しない → ブラウザによっては submit() が無視される
- input.value に objet を入れる →
[object Object]の文字列になる。事前にJSON.stringify - 改行を含む値 → hidden input でも保持される。サーバ側で正しく受け取れているか確認
- CSRF 忘れ → 419 Page Expired / 422 になる
- 同じ name を 2 つ → 後勝ち。配列にしたければ
name[]
FAQ
Q: GET でも同じやり方でできる?
A: できます。form.method = "GET" にするだけ。ただし GET は URL にパラメータが付くので、長すぎる値や秘匿情報は POST にすべき。
Q: window.location.href で POST はできる?
A: できません。location.href は GET 専用。POST 遷移したい場合は form を動的生成するこの方法が唯一の手段です。
Q: jQuery でも同じことできる?
A: $(" で同じ。ただし現代は Vanilla で十分。