JavaScriptでPOSTリクエストを確実に送信する方法:fetch APIの基本から実践まで
こんにちは、とまだです。
Webサイトでフォームを送信しようとして「送信に失敗しました」というエラーが出たり、ファイルアップロードがうまくいかなかったりした経験はありませんか?
データをサーバーに送信する作業は、重要な書類を郵送するようなものです。
正しい宛先を書き、適切な封筒に入れ、確実な配送方法を選ばないと、書類は届かないか紛失してしまいますよね。
Web開発の世界では、この「確実な配送方法」がPOSTリクエストなんです。
今回は、JavaScriptを使ってデータを安全かつ確実にサーバーに送信する方法について、じっくり解説していきます。
なぜPOSTリクエストが重要なのか?
まず、なぜPOSTリクエストを学ぶ必要があるのでしょうか。
銀行でお金を振り込む時を想像してみてください。
窓口で「○○さんの口座に10万円を振り込みたい」と口頭で伝えるのと、振込用紙にきちんと記入して手続きするのでは、どちらが安全で確実でしょうか?
当然、後者ですよね。
Web開発でも同じです。
重要なデータや大きなデータを送る時は、URLに情報を載せるGETメソッドではなく、専用の「封筒」にデータを入れて送るPOSTメソッドを使うのが基本なのです。
POSTリクエストが活躍する場面
POSTリクエストは、私たちが日常的に使っているWebサービスのあらゆる場面で活躍しています。
たとえば、SNSに写真を投稿する時。
写真データは大きいので、URLに載せることはできません。
POSTリクエストを使って、写真データを安全にサーバーに送信しているんです。
他にも、以下のような場面でPOSTリクエストが使われています。
- ユーザー登録でメールアドレスやパスワードを送信する時
- オンラインショッピングで商品を購入する時
- ブログ記事を投稿する時
- お問い合わせフォームからメッセージを送る時
これらはすべて、データをサーバーに「提出」する操作です。
そして、提出するデータには個人情報や機密情報が含まれることが多いため、安全に送信できるPOSTリクエストが使われているのです。
GETとPOSTの違いを理解しよう
ここで、GETとPOSTの違いをもう少し詳しく見てみましょう。
GETメソッド:情報を「見に行く」
GETメソッドは、図書館で本を「借りに行く」ようなイメージです。
「この本を見せてください」とお願いして、情報を取得します。
// GETは情報を「取得しに行く」
fetch('/api/users?name=田中')
.then(response => response.json())
.then(data => console.log(data));
GETメソッドの特徴として、URLに検索条件が表示されることがあります。
たとえば、Googleで「JavaScript」と検索すると、URLに「q=JavaScript」と表示されますよね。
これは、「JavaScriptについて検索してください」という情報をGETメソッドで送っているからです。
しかし、この特徴は同時に弱点でもあります。
もしパスワードをGETメソッドで送ったら、URLにパスワードが表示されてしまいます。
ブラウザの履歴にも残ってしまうので、セキュリティ上大きな問題になります。
POSTメソッド:情報を「送信する」
一方、POSTメソッドは、銀行で振込用紙を「提出する」ようなイメージです。
重要な情報を封筒(リクエストボディ)に入れて、安全に相手に届けます。
// POSTは情報を「送信する」
fetch('/api/users', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name: '田中', age: 30 })
})
.then(response => response.json())
.then(data => console.log(data));
POSTメソッドでは、送信するデータがURLには表示されません。
代わりに、HTTPリクエストの「ボディ」という見えない部分に格納されます。
これにより、パスワードやクレジットカード番号などの機密情報も安全に送信できるのです。
また、送信できるデータ量にも大きな違いがあります。
GETメソッドはURLの長さに制限があるため、送信できるデータ量は限られています。
一方、POSTメソッドは大量のデータやファイルも送信できます。
JavaScriptでPOSTリクエストを実装する方法
それでは、実際にPOSTリクエストを実装する方法を学んでいきましょう。
現代のJavaScriptでは、fetch()
という関数を使うのが一般的です。
fetch()を使った基本的な方法
まずは、最もシンプルな形から始めてみましょう。
ユーザー情報をサーバーに送信する例を見てみます。
// 基本的なPOSTリクエスト
async function sendUserData(userData) {
const response = await fetch('/api/users', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(userData)
});
const result = await response.json();
return result;
}
// 使用例
const newUser = {
name: '田中太郎',
email: 'tanaka@example.com',
age: 28
};
sendUserData(newUser);
このコードは、まるで郵便局で手紙を送るように、3つの重要な要素を指定しています。
- method: 'POST' - 「これは送信です」という指示
- headers - 「中身はJSON形式のデータです」という説明書き
- body - 実際に送るデータ(手紙の中身)
しかし、実際の開発では、これだけでは不十分です。
なぜなら、送信が失敗することもあるからです。
郵便が届かないこともあるように、ネットワークエラーやサーバーエラーが発生する可能性があります。
エラーハンドリングを追加した実装
実務では、エラーが発生した時の対処も考える必要があります。
まるで、重要な書類を送る時に「書留」や「配達証明」を使うようなものです。
async function sendUserData(userData) {
try {
const response = await fetch('/api/users', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(userData)
});
// サーバーからのレスポンスを確認
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const result = await response.json();
console.log('送信成功:', result);
return result;
} catch (error) {
console.error('送信エラー:', error);
// ユーザーにエラーを通知
alert('送信に失敗しました。もう一度お試しください。');
throw error;
}
}
このコードでは、try-catch
という仕組みを使っています。
これは「もし送信に失敗したら、こう対処してください」という指示を書いているんです。
エラーが発生した場合、ユーザーに分かりやすいメッセージを表示することで、「何が起きたのか分からない」という不安を解消できます。
フォーム送信の実装パターン
Webアプリケーションで最もよく使われるPOSTリクエストの例は、フォーム送信です。
お問い合わせフォームや会員登録フォームなど、ユーザーが入力した情報をサーバーに送信する場面ですね。
HTMLフォームとJavaScriptの連携
まず、基本的なHTMLフォームがあるとします。
<form id="contactForm">
<input type="text" name="name" placeholder="お名前" required>
<input type="email" name="email" placeholder="メールアドレス" required>
<textarea name="message" placeholder="メッセージ" required></textarea>
<button type="submit">送信</button>
</form>
このフォームをJavaScriptで制御する方法を見てみましょう。
フォーム送信は、まるで書類の提出手続きのようなものです。
必要事項を記入して、内容を確認して、最後に提出ボタンを押す。
この一連の流れをプログラムで実現します。
// フォーム要素を取得
const form = document.getElementById('contactForm');
// フォーム送信時の処理
form.addEventListener('submit', async (event) => {
// デフォルトの送信動作を停止
event.preventDefault();
// フォームデータを収集
const formData = new FormData(form);
const data = Object.fromEntries(formData.entries());
try {
// データを送信
const response = await fetch('/api/contact', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(data)
});
if (response.ok) {
alert('送信が完了しました!');
form.reset(); // フォームをクリア
} else {
throw new Error('送信に失敗しました');
}
} catch (error) {
alert('エラーが発生しました。もう一度お試しください。');
}
});
このコードのポイントは、event.preventDefault()
という部分です。
これは「ブラウザの通常の動作を一旦止めて、JavaScriptで処理を引き継ぐ」という意味です。
なぜこれが必要かというと、HTMLフォームは本来、送信ボタンを押すとページが更新されてしまうからです。
でも、現代のWebアプリケーションでは、ページを更新せずにデータを送信したいことが多いんです。
送信中の状態を表示する
ユーザー体験を向上させるために、「送信中」の状態を表示することも重要です。
郵便局で書類を提出した後、「処理中です」という表示があると安心しますよね。
同じように、Webアプリケーションでも送信中であることを知らせましょう。
form.addEventListener('submit', async (event) => {
event.preventDefault();
// 送信ボタンを取得
const submitButton = form.querySelector('button[type="submit"]');
const originalText = submitButton.textContent;
// 送信中の表示に変更
submitButton.textContent = '送信中...';
submitButton.disabled = true;
try {
// 送信処理(省略)
const response = await fetch('/api/contact', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data)
});
// 成功時の処理
} catch (error) {
// エラー処理
} finally {
// 送信ボタンを元に戻す
submitButton.textContent = originalText;
submitButton.disabled = false;
}
});
finally
ブロックは、成功しても失敗しても必ず実行される部分です。
これにより、どんな結果になってもボタンが元の状態に戻ることを保証できます。
ファイルアップロードの実装
次に、ファイルアップロードについて見てみましょう。
写真や書類をアップロードする機能は、多くのWebサービスで必要になります。
ファイルアップロードは、通常のデータ送信とは少し違います。
大きな荷物を送る時に、普通の封筒ではなく段ボール箱を使うようなイメージです。
// ファイル選択時の処理
const fileInput = document.getElementById('fileInput');
fileInput.addEventListener('change', async (event) => {
const file = event.target.files[0];
if (!file) return;
// ファイルサイズをチェック(5MB以下)
if (file.size > 5 * 1024 * 1024) {
alert('ファイルサイズは5MB以下にしてください');
return;
}
// FormDataを使ってファイルを送信
const formData = new FormData();
formData.append('file', file);
try {
const response = await fetch('/api/upload', {
method: 'POST',
body: formData
// Content-Typeは自動で設定される
});
if (response.ok) {
alert('アップロードが完了しました!');
}
} catch (error) {
alert('アップロードに失敗しました');
}
});
ファイルアップロードでは、FormData
という特別なオブジェクトを使います。
これは、ファイルを含む複雑なデータを送信するための「特別な封筒」のようなものです。
重要なのは、ファイルを送信する時はContent-Type
を指定しないことです。
ブラウザが自動的に適切な形式を設定してくれるからです。
よくあるトラブルと解決法
POSTリクエストを実装していると、様々なトラブルに遭遇することがあります。
ここでは、よくある問題とその解決方法を見ていきましょう。
CORSエラーが発生する場合
「CORSエラー」は、異なるドメイン間でデータをやり取りする時に発生します。
これは、セキュリティのための仕組みで、まるで国境での入国審査のようなものです。
適切な許可がないと、データの送信がブロックされてしまいます。
解決方法は、サーバー側で適切な設定を行うことです。
開発中は、プロキシサーバーを使うことで回避することもできます。
タイムアウトエラーへの対処
ネットワークが遅い場合や、サーバーの処理に時間がかかる場合、タイムアウトエラーが発生することがあります。
これは、郵便を送った後、いつまでも配達完了の連絡が来ない状態に似ています。
// タイムアウト機能付きのfetch
async function fetchWithTimeout(url, options = {}, timeout = 10000) {
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), timeout);
try {
const response = await fetch(url, {
...options,
signal: controller.signal
});
clearTimeout(timeoutId);
return response;
} catch (error) {
clearTimeout(timeoutId);
if (error.name === 'AbortError') {
throw new Error('リクエストがタイムアウトしました');
}
throw error;
}
}
この実装では、指定した時間(デフォルトは10秒)以内にレスポンスが返ってこない場合、自動的にリクエストをキャンセルします。
まとめ
今回は、JavaScriptでPOSTリクエストを実装する方法について解説しました。
POSTリクエストは、Webアプリケーションでデータを送信する際の基本中の基本です。
フォーム送信からファイルアップロードまで、様々な場面で活用されています。
重要なポイントをおさらいすると、このようになります。
- POSTリクエストは、重要なデータを安全に送信するための方法
- fetch APIを使えば、簡単にPOSTリクエストを実装できる
- エラーハンドリングを適切に行うことで、ユーザー体験を向上させられる
- フォーム送信やファイルアップロードなど、用途に応じた実装方法がある
これらの知識を身につければ、ユーザーが安心してデータを送信できるWebアプリケーションを作ることができます。
著者について

とまだ
フルスタックエンジニア
Learning Next の創設者。Ruby on Rails と React を中心に、プログラミング教育に情熱を注いでいます。初心者が楽しく学べる環境作りを目指しています。
著者の詳細を見る →