CORS でカスタムヘッダを送信する方法をまとめる。
CONTENTS
ENVIRONMENTS
- ruby : 2.6.1
- sinatra : 2.0.5
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
ここでは以下の流れを想定している。
https://example.com
で html を配信して、そこから ajax リクエストを受ける- Authorization ヘッダでトークンを受け取り、認証
- ファイルアップロードの処理を行い、 ID を生成
- 生成された 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
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
レスポンスヘッダ
「シンプルなレスポンスヘッダ」以外を返したい場合、 Access-Control-Expose-Headers
を含める必要がある。
これを含めないと、 xhr.getResponseHeader
や xhr.getAllResponseHeaders
でレスポンスヘッダを受け取ることができない。
ちなみにヘッダは case-insensitive なので、この例では xhr.getResponseHeader("x-upload-id")
で取得できる。
シンプルなレスポンスヘッダ
- Cache-Control
- Content-Language
- Content-Type
- Expires
- Last-Modified
- Pragma
まとめ
ヘッダを返すことをしてこなかったので Access-Content-Expose-Headers
のことを知らなかったのでまとめてみた。