【Go】EchoとNextjsを使ってCORSを学んでみた
これは何
Goのechoフレームワークの使い方を見ていたら、フレームワークの箇所にCORS
の設定があることを知りました。
これを使ってCORSに関する理解を深めたいなーと思ったので記事にします。
この記事のゴール
- echoフレームワークを使ってCORSの目的と仕組みを(ざっくり)理解する
結論
- オリジンは
スキーム+ドメイン+ポート
をセットにしたもの - デフォルトでは異なるオリジンのリソースはブラウザに共有されない
- CORSは一部のオリジンからのリクエストに対して、ブラウザにリソース共有を許可する仕組み
CORSについて
CORSはオリジン間リソース共有(Cross Origin Resource Shearing)の頭文字をとったものです。
異なるオリジンにあるリソースにアクセスする際に、アクセスを許可するか否かを決める仕組みです。
オリジンとは
そもそもオリジンとは何なのかというと
- スキーム
- ドメイン
- ポート
の3つを合わせたものをオリジンといいます。
例えば、http://example.com:80/hoge/fuga.html
というURLがあったとすると。
httpがスキーム
、example.comがドメイン
、80がポート
です。
hoge/fuga.html
の部分はパスなので関係ないです。
CORSを使う目的
CORSを使う目的は、異なるオリジンにあるリソースにアクセスを許可することです。
なぜわざわざ許可するのかというと、リソースをFetchする時には同一オリジンポリシー
というポリシーがあるためです。
同一オリジンポリシー
同一オリジンポリシーは、そのままですが、同じオリジンからのアクセスのみを許可する仕組みです。
デフォルトでこの状態になっているため、異なるオリジンからのリクエストを許可したい場合にはCORSを使う必要があります。
プリフライトリクエスト
リクエストの種類によっては、リクエストを送信する前にプリフライトリクエスト
というリクエストがブラウザによって自動的に送信されることがあります。
プリフライトリクエストはOPTIONS
メソッドを使ったリクエストで、サーバーがCORSに対応しているかどうかを確認します。
また、単純リクエストと呼ばれるリクエストを送る前にはプリフライトリクエストは送られません。
実験してみる
echo
echoはGoのWebフレームワークです。
基本的な使い方はREADMEを参照してください。
今回はechoのミドルウェア機能を使ってCORSを実現したいと思います。
バックエンドの実装
以下がバックエンドの実装例です。
func getHello(c echo.Context) error {
return c.JSON(http.StatusOK, map[string]string{"message": "get hello world"})
}
func main() {
e := echo.New()
// ミドルウェアを使ってCORSの設定をする
e.Use(middleware.CORSWithConfig(middleware.CORSConfig{
// http://example.comのオリジンのみを許可
AllowOrigins: []string{"http://example.com"},
// Oigin,ContentType,Acceptのヘッダを許可
AllowHeaders: []string{echo.HeaderOrigin, echo.HeaderContentType, echo.HeaderAccept},
}))
e.GET("/getHello", getHello)
e.Logger.Fatal(e.Start(":8090"))
}
まず、getHello
というハンドラを用意しました。
それぞれ、/getHello
GETでアクセスしたときのハンドラになっています。
CORSを設定しているのはUse
というメソッドを使っている部分です。
http://example.com
というオリジンのみを許可しています。
また、e.Use(middleware.CORS())
とするとecho側で用意されたデフォルトの設定となり、どんなオリジンからのアクセスも許可するようになります。
フロントエンドの実装
続いてフロントエンドの実装例です。
今回はNext.jsのfetch
を使ってAPIを実行します。
const getFromEcho = async () => {
const response = await fetch("http://localhost:8090/getHello")
return response
}
const CorsTest = () => {
const response = getFromEcho()
return (
<>
<h1>CORS Test Page</h1>
</>
)
}
getFromEcho
とサーバーへのGETするメソッドになっています。
pages/CorsTest/index.tsx
というパスでファイルを作成したので、localhost:3000/CorsTest
にアクセスすると画面が表示されてバックエンドサーバーにリクエストが送信されます。
結果
localhost:3000/CorsTest
にアクセスし、デベロッパーツールのネットワークを見てみると以下のようなレスポンスが返ってきています。
http://localhost:3000
からのアクセスは許可していないのでCORSエラーになりました。
CORSを許可
func main() {
e := echo.New()
e.Use(middleware.CORSWithConfig(middleware.CORSConfig{
// http://localhost:3000を許可
AllowOrigins: []string{"http://localhost:3000"},
AllowHeaders: []string{echo.HeaderOrigin, echo.HeaderContentType, echo.HeaderAccept },
}))
e.GET("/getHello", getHello)
e.Logger.Fatal(e.Start(":8090"))
}
AllowOrigins
の部分をhttp://localhost:3000
を許可するように変えました。
これでリクエストすると正常なレスポンスが返ってきました。
中身は以下のようになっていました。
Access-Control-Allow-Origin
ヘッダにlocalhost:3000が入っています。
最後に
簡単にではありますが、CORSの仕組みについて実験しながらざっくり理解できたと思います。
ヘッダの内容など触れていない部分もまだまだたくさんあるので、今後も勉強していきたいと思いました!
少しでも参考になれば幸いです!
Discussion