フォーム送信とJSON APIのHTTPの違い

入門 | 11分 で読める | 2026.06.26

公式ドキュメント

今回やること

この記事では、フォーム送信とJSON APIのHTTP上の違いを確認します。

同じPOSTでも、HTMLフォーム、JSON API、ファイルアップロードでは、送られるContent-Typeとボディの形が違います。

「POSTしているのにサーバーで値が取れない」という不具合は、この違いを見落としていると起きやすいです。

3つの送信パターン

Webアプリでよく見る送信パターンは次の3つです。

パターン主なContent-Typeよく使う場面
通常のフォームapplication/x-www-form-urlencoded問い合わせ、検索、ログイン
JSON APIapplication/jsonSPA、モバイルアプリ、外部API
ファイルアップロードmultipart/form-data画像、PDF、添付ファイル

どれもHTTPリクエストですが、サーバー側の受け取り方が変わります。

通常フォームのGET

検索フォームでは、GET がよく使われます。

<form action="/search" method="get">
  <input name="q" value="javascript">
  <button>検索</button>
</form>

送信後のURLは次のようになります。

/search?q=javascript

HTTPとして見ると、本文ではなくクエリに値が入ります。

GET /search?q=javascript HTTP/1.1
Host: example.com

GETフォームは、検索条件や絞り込み条件のように、URLで共有しても問題ない情報に向いています。パスワード、住所、電話番号、問い合わせ本文のような情報をGETで送るのは避けます。

通常フォームのPOST

問い合わせやログインでは、POST がよく使われます。

<form action="/contact" method="post">
  <input name="name" value="Ada">
  <textarea name="message">hello</textarea>
  <button>送信</button>
</form>

この場合、HTTPリクエストは次のような形になります。

POST /contact HTTP/1.1
Host: example.com
Content-Type: application/x-www-form-urlencoded

name=Ada&message=hello

application/x-www-form-urlencoded は、フォームの値を key=value&key=value の形で送る形式です。

サーバー側では、HTMLフォームを処理する仕組みで本文を読み取ります。JSONとして読む処理だけを書いていると、この形式の値を受け取れないことがあります。

JSON APIのPOST

JavaScriptの fetch でAPIに送る場合は、JSONがよく使われます。

await fetch("/api/contact", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "Accept": "application/json"
  },
  body: JSON.stringify({
    name: "Ada",
    message: "hello"
  })
});

HTTPとして見ると、次のようになります。

POST /api/contact HTTP/1.1
Host: example.com
Accept: application/json
Content-Type: application/json

{"name":"Ada","message":"hello"}

JSON APIでは、Content-Type: application/json とJSON文字列の本文がセットです。

よくあるミス:

ミス起きること
JSON.stringify しないbodyが想定通りの文字列にならない
Content-Type を付け忘れるサーバーがJSONとして読まない
キー名が違うバリデーションエラーになる
Accept を指定しないHTMLエラーが返ることがある

POST しているかどうかだけでなく、本文がどの形式で送られているかを確認します。

ファイルアップロード

画像やPDFを送る場合は、multipart/form-data が使われます。

<form action="/profile/avatar" method="post" enctype="multipart/form-data">
  <input type="file" name="avatar">
  <button>アップロード</button>
</form>

HTTPとしては、複数の部品に分かれた本文になります。

POST /profile/avatar HTTP/1.1
Host: example.com
Content-Type: multipart/form-data; boundary=----abc

------abc
Content-Disposition: form-data; name="avatar"; filename="profile.png"
Content-Type: image/png

...binary...
------abc--

multipart/form-data では、ブラウザが boundary を付けて本文を区切ります。

JavaScriptで FormData を使う場合、通常は Content-Type を手動で設定しません。手動で multipart/form-data だけを書いてしまうと、必要な boundary が欠けてサーバーが読めないことがあります。

const formData = new FormData();
formData.append("avatar", file);

await fetch("/profile/avatar", {
  method: "POST",
  body: formData
});

JSON APIとフォームの使い分け

どちらが正しいというより、用途で選びます。

用途向いている形式
通常のWebページ内フォームHTMLフォーム
JavaScript中心の画面JSON API
外部システムと連携JSON API
ファイルアップロードmultipart/form-data
検索や絞り込みGET + クエリ

初学者が混乱しやすいのは、画面では同じ「送信ボタン」に見えても、HTTP上ではかなり違う形になる点です。

DevToolsで確認する場所

Chrome DevToolsのNetworkパネルで対象リクエストを選びます。

見たいもの場所
メソッドHeaders > General
URLHeaders > General
Content-TypeHeaders > Request Headers
クエリPayload または Headers
フォーム本文Payload
JSON本文Payload
ファイル送信Payload

送信できていないように見えるときは、まずNetworkにリクエストが出ているかを確認します。リクエスト自体が出ていなければ、JavaScriptエラー、フォームのイベント処理、ボタンの種類などを見ます。

curlで比べる

フォーム形式で送る例:

curl -X POST https://example.com/contact \
  -H "Content-Type: application/x-www-form-urlencoded" \
  --data "name=Ada&message=hello"

JSONで送る例:

curl -X POST https://example.com/api/contact \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  --data '{"name":"Ada","message":"hello"}'

ファイルを送る例:

curl -X POST https://example.com/profile/avatar \
  -F "avatar=@profile.png"

curl でも、フォーム形式、JSON、ファイルアップロードで指定の仕方が変わります。ブラウザで送っている内容と同じ形を再現できると、フロント側の問題かサーバー側の問題かを切り分けやすくなります。

よくある不具合

症状よくある原因
サーバーで値が空になるContent-Type と本文形式が合っていない
JSON parse errorJSONとして不正な文字列を送っている
415 Unsupported Media Typeサーバーがその形式を受け付けていない
ファイルが空になるmultipart/form-data の扱いが間違っている
ログイン後に戻されるCookieが送られていない
CORSで止まるブラウザのオリジン制限に引っかかっている

400415 が返ったときは、サーバーが悪いと決めつけず、リクエストの形式を先に確認します。

まとめ

HTMLフォーム、JSON API、ファイルアップロードは、同じHTTP通信でもリクエストの形が違います。

確認するポイントは、メソッド、URL、Content-Type、ボディの形式です。特に POST の不具合では、「POSTしているか」よりも「何形式でPOSTしているか」を見ることが重要です。

参考リソース

← 一覧に戻る
PR
PR
PR
PR