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```に対する設定を記述する。

```conf
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に転送する設定。
![スクリーンショット 2020-10-13 22.54.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/349293/47d0b9e2-ac9c-7d73-7487-da476a71159a.png)

### 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 Request```と```Preflight Request```の2種類に分けられる。```Preflight Request```の場合、サーバー側で許可する設定が必要
② リクエストヘッダーに独自のヘッダーを追加する場合（今回のケースだと```key```）は、サーバー側でそれを許可する設定が必要

#### ① の解決
これについてはこのサイトが大変参考になりました。
[CORS(Cross-Origin Resource Sharing)について整理してみた](https://dev.classmethod.jp/articles/about-cors/)

> 以下の条件の全てに該当する場合、ブラウザは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```の部分）。

#### ② の解決
メソッドを許可したのと同様に、ヘッダーの許可も必要になります。
[こちらのサイト](https://developer.mozilla.org/ja/docs/Web/HTTP/Headers/Access-Control-Allow-Headers)には次のような記述があります。

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

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

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

## _参考_
[CORSまとめ](https://qiita.com/tomoyukilabs/items/81698edd5812ff6acb34)
[なんとなく CORS がわかる...はもう終わりにする。](https://qiita.com/att55/items/2154a8aad8bf1409db2b)
[CORS(Cross-Origin Resource Sharing)について整理してみた](https://dev.classmethod.jp/articles/about-cors/)
[MDN web docs](https://developer.mozilla.org/ja/docs/Web/HTTP/Headers/Access-Control-Allow-Headers)
（ありがとうございました..)