CORSエラーってなに?どうすれば解決するの?


はじめに

皆さんはブラウザからAPIを実行する際に以下のようなエラーに遭遇したことはないですか?

Access to XMLHttpRequest at 'http://localhost:3065/user' from origin 'http://localhost:3000' 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.

これはCORSと呼ばれるポリシーによるエラーですが、自分自身も何度がこのエラーに遭遇したことはありましたが、深く理解しておらず、なんとなく解決してました。
今回は実際にCORSについて解説と解決方法について実演を交えながら記事にしていきたいと思います。

そもそもCORSってなんなの?

ブラウザはSORS(Same-Origin Resource shareing)という仕組みを実装していて、異なるオリジン(Cross-origin)間へのリソースへのアクセスを制限しています。
なぜ、制限しているかというと、クロスサイトサージェリーなどのセキュリティ攻撃を防止するためです。
で、CORS(Cross-origin resource sharing)が何なのかというと、このSORSの制約を一部解除することで異なるオリジンへのリソースのアクセスを許可したものです。

CORSエラーを発生させてみる

実験環境構築手順

今回の環境は
http://localhost:8100 (以後、Aとする)のwebページからtestというボタンをクリックすると
Aというオリジンから、 
http://localhost:8030  (以後、Bとする)という異なるオリジンへのアクセスし、アクセスに成功するとbackendという文字列を表示させるためのものになります。

  • gitレポジトリをclone
$ git clone https://github.com/hgaiji/CORS-test
  • コンテナ環境を起動
$ docker-compose up -d
  • Aにブラウザからアクセス

以下のような画面が表示されているかと思います。

  • 開発者コンソールを開く

webページにアクセスしたら、開発者コンソールにアクセスして、consoleタブを開きます。

  • アクセスしてみる  

先程説明した通り、異なるオリジンへのアクセスしようとしているのでCORSエラーが発生するはずです。

では実際にA(http://localhost:8100) からB(http://localhost:8030) にアクセスしてCORSエラーが発生するか見てみます。

すると、開発者コンソールのconsoleタブに以下のようなエラーが発生し、backendという文字列が表示されていないかと思います。

Access to XMLHttpRequest at 'http://localhost:8030/' from origin 'http://localhost:8100' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

これがCORSエラーです!

CORSの仕組み(CORSの設定)

http://localhost:8100 から http://localhost:8070 へリクエストするときはリクエストヘッダにorigin:http://localhost:8100 が付与されます。(developerツールのheaderタブから確認できます。)

http://localhost:8070 側で、http://localhost:8100 へのアクセスを許可する場合(CORSの設定)、下記の様にレスポンスヘッダを付与するように設定します。

Access-Control-Allow-Origin: http://localhost:8100

実際に設定してみます。
app.go内に以下の設定を追加してみましょう。

app.go
// test
func test(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Content-Type", "application/json")
    w.Header().Set("Access-Control-Allow-Origin", "http://localhost:8100")
    w.Write([]byte("backend"))
}

こちらで、testボタンをクリックすると無事にアクセスできました。

まとめ

  • CORS
    • ブラウザのポリシーで異なるオリジンへのアクセスを許可するもの
  • CORSエラーの解決方法
    • アクセスを受ける側(サーバー側に)レスポンスヘッダにAccess-Control-Allow-Originヘッダを付与する設定を追加する