げっとシステムログ

WEB開発メモ

CORS でカスタムヘッダを送受信する

CORS でカスタムヘッダを送信する方法をまとめる。

CONTENTS
  1. sinatra でのサンプル
  2. preflight レスポンスヘッダ
  3. レスポンスヘッダ
  4. まとめ
  5. 参考資料
ENVIRONMENTS
  • ruby : 2.6.1
  • sinatra : 2.0.5

TOP

sinatra でのサンプル

まず sinatra でのサンプルを示す。

require "sinatra"

options "*" do
  headers(
    "Access-Control-Allow-Origin" => "https://example.com",
    "Access-Control-Allow-Methods" => "GET,POST,PUT,DELETE,OPTIONS,HEAD",
    "Access-Control-Allow-Headers" => "Authorization",
  )
end

post "/upload" do
  headers(
    "Access-Control-Allow-Origin" => "https://example.com",
    "Access-Control-Expose-Headers" => "X-Upload-ID",
  )

  halt 401 unless authorize(env["HTTP_AUTHORIZATION"]) # authorize by token

  halt 400 unless file = (params[:file] && params[:file][:tempfile])

  upload_id = upload file # process uploaded file...

  headers["X-Upload-ID"] = upload_id.to_s

  content_type "application/json"
  { message: :ok }.to_json
end

ここでは以下の流れを想定している。

  1. https://example.com で html を配信して、そこから ajax リクエストを受ける
  2. Authorization ヘッダでトークンを受け取り、認証
  3. ファイルアップロードの処理を行い、 ID を生成
  4. 生成された ID を X-Upload-ID ヘッダで返す

これは「シンプルなリクエスト」ではないので、ブラウザは preflight リクエストを行う。

シンプルなリクエスト

「シンプルなリクエスト」は以下を満たす。

  • 以下のメソッドのうち、いずれかである
    • HEAD
    • GET
    • POST
  • 以下のヘッダ以外を含まない
    • Accept
    • Accept-Language
    • Content-Language
    • Content-Type
    • Last-Event-ID
  • 以下の Content-Type のうち、いずれかである
    • application/x-www-form-urlencoded
    • multipart/form-data
    • text/plain

TOP

preflight レスポンスヘッダ

「シンプルなリクエスト」以外のリクエストをする場合、ブラウザは preflight リクエストを行う。 preflight リクエストは対象のリソースに対して OPTIONS メソッドでリクエストの可否を問い合わせる。

この時、サーバーは以下のヘッダを含めて応答する。

  • Access-Control-Allow-Origin : アクセスを許可する Origin
  • Access-Control-Allow-Methods : アクセスを許可する Method
  • Access-Control-Allow-Headers : 含めて良い Header

Access-Control-Allow-Headers に関してはを「シンプルなリクエストヘッダ」は常に許可されるので列挙する必要はない。

ブラウザは、このレスポンスヘッダで許可されたリクエストのみサーバーに発行する。

シンプルなリクエストヘッダ

  • Accept
  • Accept-Language
  • Content-Language
  • Content-Type は以下のうち、いずれかである
    • application/x-www-form-urlencoded
    • multipart/form-data
    • text/plain

TOP

レスポンスヘッダ

「シンプルなレスポンスヘッダ」以外を返したい場合、 Access-Control-Expose-Headers を含める必要がある。 これを含めないと、 xhr.getResponseHeaderxhr.getAllResponseHeaders でレスポンスヘッダを受け取ることができない。

ちなみにヘッダは case-insensitive なので、この例では xhr.getResponseHeader("x-upload-id") で取得できる。

シンプルなレスポンスヘッダ

  • Cache-Control
  • Content-Language
  • Content-Type
  • Expires
  • Last-Modified
  • Pragma

TOP

まとめ

ヘッダを返すことをしてこなかったので Access-Content-Expose-Headers のことを知らなかったのでまとめてみた。

TOP

参考資料

TOP