プリフライトリクエストを使用してAPIにリクエスト

2025年9月18日

そもそもHTTP リクエストとは?

XMLHttpRequest

HTTP リクエストの手段は何がある?

XMLHttpRequestでは異なるドメインでアクセス、レスポンスの読み込みができません

プリフライトリクエストとは

  • 本リクエストの前に送る確認用の OPTIONS リクエスト。
  • 「対象サーバーがそのクロスオリジンのリクエストを許可するかどうか」のCORSポリシーを事前に確認する目的で送られます

どのような場合に場合にプリフライトリクエストが送信されるか?

ステータスコード

HTTPのレスポンスヘッダの先頭に必ず入ってます

ステータスコード名前説明
200OKリクエスト成功
202Acceptedリクエスト成功したが、処理はまだ
301Moved Permanentlyリソースは恒久的に移動
302Foundリクエストしたリソースは一時的に移動
307Temporary Redirectリクエストしたリソースは一時的に移動
400Bad Requestリクエストが正しくない
403Forbiddenアクセスが禁止されている
404Not Found指定したリソースが見つからない
405Method Not Allowed指定したメソッドを使えません
406Not AcceptableAccept関連のヘッダに問題
413Request Entity Too Largeリクエストボディが大きすぎる
415Unsupported Media Typeサポートしていないメディアタイプ
429Too Many Requestsリクエスト回数が多すぎる
500Internal Server Errorサーバー側でエラーが発生
503Service Unavailableサーバーが一時的に停止

より詳細は下記を参照

HTTP response status codes - HTTP | MDN

HTTP response status codes indicate whet…
developer.mozilla.org

CORS と同一オリジンポリシー

Web ブラウザには同一オリジンポリシーがあり、異なるオリジン間のリソースアクセスは制限されます。CORS(Cross-Origin Resource Sharing)は、サーバーが特定の外部オリジンからのアクセスを許可する仕組みです。プリフライトは、この CORS 許可可否を事前確認するための仕組みです。

オリジン間リソース共有 (CORS) - HTTP | MDN

オリジン間リソース共有 (Cross-Origin Resource Shari…
developer.mozilla.org

プリフライトの流れ

  1. ブラウザが OPTIONS メソッドで以下のヘッダーを送信:
  • Origin: 要求元オリジン(例: https://app.example.com
  • Access-Control-Request-Method: これから送る本リクエストの HTTP メソッド
  • Access-Control-Request-Headers: 本リクエストで送る予定のカスタムヘッダー一覧
  1. サーバーは許可する場合、以下のヘッダーを含めて 200 などで応答:
  • Access-Control-Allow-Origin: 許可するオリジン(* も可。ただし認証絡みでは制約あり)
  • Access-Control-Allow-Methods: 許可するメソッド
  • Access-Control-Allow-Headers: 許可するリクエストヘッダー
  • Access-Control-Max-Age: プリフライト結果のキャッシュ秒数
  • 必要に応じて Access-Control-Allow-Credentials: true
  1. ブラウザは許可を確認できたら、本リクエスト(GET/POST/PUT/...)を送信します。

ブラウザからの例(fetch)

await fetch('https://api.example.com/users', {
  method: 'PUT',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': 'Bearer <token>',
  },
  body: JSON.stringify({ name: 'Taro' }),
  credentials: 'include', // クッキーを伴う場合
});

上記は PUTAuthorization によりプリフライトが発生します。



サーバー側の設定例

Apache (httpd)

mod_headers を有効化のうえ、<VirtualHost> などで設定:

<IfModule mod_headers.c>
  Header always set Access-Control-Allow-Origin "https://app.example.com"
  Header always set Access-Control-Allow-Methods "GET,POST,PUT,DELETE,OPTIONS"
  Header always set Access-Control-Allow-Headers "content-type,authorization"
  Header always set Access-Control-Allow-Credentials "true"
  Header always set Access-Control-Max-Age "86400"

  # OPTIONS には即時応答(必要に応じて)
  <If "%{REQUEST_METHOD} == 'OPTIONS'">
    Header always set Content-Length "0"
  </If>
</IfModule>

Nginx

location / {
  if ($request_method = OPTIONS) {
    add_header Access-Control-Allow-Origin "https://app.example.com" always;
    add_header Access-Control-Allow-Methods "GET,POST,PUT,DELETE,OPTIONS" always;
    add_header Access-Control-Allow-Headers "content-type,authorization" always;
    add_header Access-Control-Allow-Credentials "true" always;
    add_header Access-Control-Max-Age 86400 always;
    return 204;
  }

  add_header Access-Control-Allow-Origin "https://app.example.com" always;
  add_header Access-Control-Allow-Credentials "true" always;
}

Node.js (Express)

import express from 'express';
import cors from 'cors';

const app = express();
app.use(cors({
  origin: 'https://app.example.com',
  methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
  allowedHeaders: ['content-type', 'authorization'],
  credentials: true,
  maxAge: 86400,
}));

app.listen(3000);

PHP(フレームワーク未使用の素朴な例)

<?php
$origin = 'https://app.example.com';

header('Access-Control-Allow-Origin: ' . $origin);
header('Access-Control-Allow-Credentials: true');
header('Vary: Origin');

if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
    header('Access-Control-Allow-Methods: GET,POST,PUT,DELETE,OPTIONS');
    header('Access-Control-Allow-Headers: content-type,authorization');
    header('Access-Control-Max-Age: 86400');
    http_response_code(204);
    exit;
}

// 以降に本処理

トラブルシューティング

  • ブラウザの開発者ツールのネットワークタブで OPTIONS 応答を確認
  • curl で再現:
curl -i -X OPTIONS \
  -H "Origin: https://app.example.com" \
  -H "Access-Control-Request-Method: PUT" \
  -H "Access-Control-Request-Headers: content-type,authorization" \
  https://api.example.com/users