🌐

HTTPカスタムヘッダーを追加してクライアントとサーバー間でデータをやり取りするときのCORS設定

2024/04/25に公開

はじめに

HTTPリクエスト時にカスタムヘッダーを追加してクライアントとサーバー間でデータをやりとりしたい場合に必要なCORS設定についてまとめました。

この記事が参考になるかもしれない人

  • クライアント側でカスタムヘッダーに値をセットして、サーバー側からアクセスしたい
  • サーバー側でカスタムヘッダーに値をセットして、クライアント側からアクセスしたい

この記事では触れないこと

  • CORS(Cross-Origin Resource Sharing)の説明や仕組み
  • プリフライトリクエストと単純リクエスト

結論

  • クライアント側でカスタムヘッダーに値をセットして、サーバー側からアクセスしたい
    CORS設定のAccess-Control-Allow-Headersに追加したいヘッダーを設定
  • サーバー側でカスタムヘッダーに値をセットして、クライアント側からアクセスしたい
    CORS設定のAccess-Control-Expose-Headersに追加したいヘッダーを設定

クライアント側でカスタムヘッダーに値をセットして、サーバー側からアクセスしたい

必要なCORS設定:Access-Control-Allow-Headers
Access-Control-Allow-Headersの設定が抜けていると、セキュアでないヘッダーが含まれていると判断されてサーバー側でリクエストが拒否されてしまいます。

CORSのデフォルト設定で許可されているヘッダーは Accept, Accept-Language, Content-Language,Content-Typeです。
これ以外のヘッダーを扱いたい場合はAccess-Control-Allow-Headersに追加する必要があります。例えばよく利用されそうなAuthorizationAccess-Control-Allow-Headersに含める必要があります。ちなみにAuthorizationAccess-Control-Allow-Headers: *で表すことができない(ワイルドカードに含まれない)ので明示する必要があります。

以下はソースコードのイメージです。
my-allow-header, x-api-key というヘッダーをセットしてクライアントからリクエストしています。

    // クライアント側からカスタムヘッダーをセットしてリクエスト
    const url = 'http://localhost:8080/test';
    const res = await axios.post(
      url,
      {
        param: 'param',
      },
      {
        headers: {
          'my-allow-header': 'myHeader',
          'x-api-key': 'MyAPIKey',
        },
      },
    );

サーバー側はmy-allow-header, x-api-keyAccess-Control-Allow-Headersに追加しています。

// サーバー側のCORS設定
func Cors() gin.HandlerFunc {
	config := cors.DefaultConfig()
        // Access-Control-Allow-Originの設定
	config.AllowOrigins = strings.Split(os.Getenv("CORS_ALLOW_ORIGINS"), ",")
        // Access-Control-Allow-Headersの設定
	config.AllowHeaders = []string{"Content-Type", "Authorization", "my-allow-header","x-api-key"}

	return cors.New(cors.Config(config))
}

許可されていないヘッダーを含むリクエストを送信した場合、ブラウザの検証ツールにはこのように表示されています。


Chromeの検証ツールで確認した場合

サーバー側でカスタムヘッダーに値をセットして、クライアント側からアクセスしたい

必要なCORS設定:Access-Control-Expose-Headers
Access-Control-Expose-Headersの設定が抜けているとクライアントからカスタムヘッダーにアクセスすることができません。

クライアントがデフォルトでアクセスできるヘッダーは Cache-ControlContent-LanguageContent-LengthContent-TypeExpiresLast-ModifiedPragmaです。
これ以外のヘッダーにアクセスしたい場合はAccess-Control-Expose-Headersに列挙する必要があります。Access-Control-Allow-Headersと同じく、Authorizationはワイルドカードの対象にならないので明示する必要があります。

以下はソースコードのイメージです。
サーバー側のCORS設定で Access-Control-Expose-Headersx-my-expose-headerヘッダーを追加します。

// サーバー側のCORS設定
func Cors() gin.HandlerFunc {
	config := cors.DefaultConfig()
        // Access-Control-Allow-Originの設定
	config.AllowOrigins = strings.Split(os.Getenv("CORS_ALLOW_ORIGINS"), ",")

        // Access-Control-Expose-Headersの設定
	config.ExposeHeaders = []string{"x-my-expose-header"}

	return cors.New(cors.Config(config))
}

ヘッダーにx-my-expose-header: my, expose, header をセットしてリクエストしてみます。

// カスタムヘッダーを追加して値をセット
func SetMyHeader() gin.HandlerFunc {
	return func(c *gin.Context) {
		header := c.Writer.Header()
		header["x-my-expose-header"] = []string{"my", "expose", "header"}
	}
}

クライアント側ではカスタムヘッダーx-my-expose-headerにアクセスするだけです。

// フロントエンド側でカスタムヘッダーにアクセス
const url = 'http://localhost:8080/get-test';
const response = await axios.get(url);

console.log(response.headers);

const result = response.headers['x-my-expose-header']

レスポンスヘッダーをconsole.logで出力してみると、x-my-expose-headerが存在していることが確認できます。


クライアント側でちゃんとヘッダーにアクセスできることを確認してみる

まとめ

HTTPリクエスト周りで変更を加えたい&期待した挙動にならないときはCORSの設定を確認!

参考

https://developer.mozilla.org/ja/docs/Web/HTTP/CORS
https://qiita.com/tomoyukilabs/items/81698edd5812ff6acb34

レスキューナウテックブログ

Discussion