headers に独自のキーを追加してリクエストを送る


0. 環境

nginx:1.18.0
vue.js:2.6.12

1. 概要

ALB + ec2(nginx+gunicorn+flask) の構成でデプロイし、ALBにてリクエストヘッダーを確認し、アクセス制限をかけるのがゴールでした。UI側は cloudfront + s3 でデプロイ済みで、ここからサーバーにリクエストを送ります。
リクエストを送る際に cors のエラーが発生し、解決に時間がかかってしまったので、備忘録として書いておきます。

  • 発生したエラー
Access to XMLHttpRequest at 'http://xxx.xxx.elb.amazonaws.com/yyy' from origin 'http://localhost:8080' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.

2. 結論

nginx の設定(confファイル)にPreflight Requestに対する設定を記述する。

location / {
      # preflightに対するレスポンス指定
      if ($request_method = 'OPTIONS') {
          add_header Access-Control-Allow-Origin '*'; # corsの許可
          add_header Access-Control-Allow-Methods 'GET, POST, PUT, DELETE'; # メソッドの許可
          add_header Access-Control-Allow-Headers 'Origin, Authorization, Accept, Content-Type, key'; # ここにヘッダーに追加するキーを追加する!
          add_header Access-Control-Max-Age 3600;
      ...

3. 各種設定・コードの確認

3.1 ALBの設定

ALB ではヘッダーにkey=valueが含まれている場合は、ec2に転送する設定。

3.2 UI(vue.js)側のリクエストコード

ヘッダーにkeyを追加し、axios で ALB に GETリクエストを送信。

vue.js
let config = {
  headers: {
    'key': 'value'
  },
};
this.axios
  .get('http://xxx.xxx.elb.amazonaws.com/hello', config)
  .then((response) => {
    console.log(response)
...

4. ハマった点・解決方法

① CORS のリクエストはSimple RequestPreflight Requestの2種類に分けられる。Preflight Requestの場合、サーバー側で許可する設定が必要
② リクエストヘッダーに独自のヘッダーを追加する場合(今回のケースだとkey)は、サーバー側でそれを許可する設定が必要

① の解決

これについてはこのサイトが大変参考になりました。
CORS(Cross-Origin Resource Sharing)について整理してみた

以下の条件の全てに該当する場合、ブラウザはpreflightリクエストを送る必要がないと判断し、シンプルなリクエストを送信します。それ以外の場合は、preflightリクエストを送信します。

・ HTTPメソッドがGET, POST, HEADのいずれか
・ HTTPヘッダにAccept, Accept-Language, Content-Language, Content-Type以外のフィールドが含まれない
・ Content-Typeの値はapplication/x-www-form-urlencoded, multipart/form-data, text/plainのいずれか

今回のケースだとリクエストヘッダーにkeyが入っているため Preflight Request とみなされます。なおPreflight Requestのレスポンスには、アクセス許可するメソッドをレスポンスヘッダに含める必要があるようです(結論のコードAccess-Control-Allow-Methodsの部分)。

② の解決

メソッドを許可したのと同様に、ヘッダーの許可も必要になります。
こちらのサイトには次のような記述があります。

CORS セーフリストリクエストヘッダー, Accept, Accept-Language, Content-Language, Content-Type は常に許可されており、このヘッダーで列挙する必要はありません。

上記のヘッダー以外はデフォルトでは許可されていないようです。今回のケースではkeyを許可したいので追加します(結論のコードAccess-Control-Allow-Headersの部分)。

5. 感想

CORSについてあまり理解していなかったので、解決にかなり時間を費やしてしまいました。
間違っている点、補足等あればコメントを頂きたいです!

参考

CORSまとめ
なんとなく CORS がわかる...はもう終わりにする。
CORS(Cross-Origin Resource Sharing)について整理してみた
MDN web docs
(ありがとうございました..)