Gin echo corsのオリジンをHttp Request から取得する

今回は Go のwebフレームワーク Gin, echo でCORSの設定を行う時にhttp Request からoriginを取得してHeaderに付与する方法を見ていきます。

発端はvercelのプレビュー環境(ランダムなURL)でもクライアントからAPIを叩けるようにする為でした。

*cookieを送信するようにするため、access-control-allow-credentialsをtrueにした場合、allow-originにはワイルドカードを使うことができません。

また、GinやechoのフレームワークはCORSをいい感じに設定してくれるメソッドを提供していますが、そちらを使用した場合あらかじめoriginを設定する必要がありました。どのようにカスタマイズするかも合わせて見ていきます。

なお、今回はCORS自体の説明はしないので復習したい方はこちらの記事がおすすめです。

qiita.com

ソースコード

Ginの場合

カスタム前

func NewCors() gin.HandlerFunc {
    return cors.New(cors.Config{
        AllowOrigins:[]string{"http://localhost:3000", "http://localhost:3001"},
        AllowMethods: []string{"GET", "POST"},
        AllowHeaders: []string{
            "Origin",
            "Content-Length",
            "Content-Type",
            "Authorization",
        },
        AllowCredentials: true,
        MaxAge:           12 * time.Hour,
    })
}

カスタム後

func NewCors() gin.HandlerFunc {
    return func(c *gin.Context) {
        c.Writer.Header().Set("Access-Control-Allow-Origin", c.Request.Header.Get("Origin"))
        c.Writer.Header().Set("Access-Control-Max-Age", "12h0m0s")
        c.Writer.Header().Set("Access-Control-Allow-Methods", "POST, GET")
        c.Writer.Header().Set("Access-Control-Allow-Headers", "Origin, Content-Type, Content-Length, Authorization")
        c.Writer.Header().Set("Access-Control-Expose-Headers", "Content-Length")
        c.Writer.Header().Set("Access-Control-Allow-Credentials", "true")

        if c.Request.Method == http.MethodOptions {
            c.AbortWithStatus(204)
            return
        }
        c.Next()
    }
}

echoの場合

カスタム前

func NewCors() echo.MiddlewareFunc {
    return middleware.CORSWithConfig(middleware.CORSConfig{
        AllowOrigins:[]string{"http://localhost:3000", "http://localhost:3001"},
        AllowHeaders: []string{echo.HeaderOrigin, echo.HeaderContentType, echo.HeaderAccept},
        AllowCredentials: true,
        MaxAge:           43200,
    })
}

カスタム後

func NewCors() echo.MiddlewareFunc {
    return func(next echo.HandlerFunc) echo.HandlerFunc {

        return func(c echo.Context) error {
            c.Response().Writer.Header().Set("Access-Control-Allow-Origin", c.Request().Header.Get("Origin"))
            c.Response().Header().Set("Access-Control-Max-Age", "12h0m0s")
            c.Response().Header().Set("Access-Control-Allow-Methods", "POST, GET")
            c.Response().Header().Set("Access-Control-Allow-Headers", "Origin, Content-Type, Content-Length, Authorization")
            c.Response().Header().Set("Access-Control-Expose-Headers", "Content-Length")
            c.Response().Header().Set("Access-Control-Allow-Credentials", "true")


            if c.Request().Method == http.MethodOptions {
                return c.NoContent(http.StatusNoContent)
            }

            return next(c)
        }
    }
}
  • カスタム前: フレームワーク提供のメソッドを使用 originは指定しなければならない

  • カスタム後: Http Request からoriginを取得する 実質ワイルドカードで全許可するのと同じ


いずれも以下のコードでhttp.Headerからoriginを取得しています。

c.Request().Header.Get("Origin")



ヘッダーを付与した後は プリフライトリクエストの"OPTION"メソッドで204を返すようにしています。

これでどのoriginからでもAPIを叩くことができますね!



Ginやechoはwebフレームワークとしては軽量なのでカスタマイズがしやすいと思います。 その分net/http など標準パッケージの理解を深める事が大事だと思いました。

内容は以上となります。


最後に、 このブログではweb開発について発信していくのでまたご覧頂けると嬉しいです。 最後までお読み頂きありがとうございました。

参考記事

Go gin framework CORS - Stack Overflow