🔒

【Go】EchoとNextjsを使ってCORSを学んでみた

2024/03/27に公開

これは何

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を参照してください。
https://github.com/labstack/echo
今回はechoのミドルウェア機能を使ってCORSを実現したいと思います。
https://echo.labstack.com/docs/middleware/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というハンドラを用意しました。
それぞれ、/getHelloGETでアクセスしたときのハンドラになっています。
CORSを設定しているのはUseというメソッドを使っている部分です。
http://example.comというオリジンのみを許可しています。
また、e.Use(middleware.CORS())とするとecho側で用意されたデフォルトの設定となり、どんなオリジンからのアクセスも許可するようになります。

フロントエンドの実装

続いてフロントエンドの実装例です。
今回はNext.jsのfetchを使ってAPIを実行します。

pages/CorsTest/index.tsx
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の仕組みについて実験しながらざっくり理解できたと思います。
ヘッダの内容など触れていない部分もまだまだたくさんあるので、今後も勉強していきたいと思いました!
少しでも参考になれば幸いです!

GitHubで編集を提案

Discussion