GoのWebフレームワーク Echo で CORS を設定する
はじめに
最近、Echoで個人開発をしていて(最近の記事に記載)CORSの設定をまだしていなかったので今回追加しました。 CORSについても改めて整理。
CORSについて
■ CORSとは
- Cross-Origin Resource Sharing の略
- あるオリジンで読み込まれたリソースのhtml 、スクリプトなどが異なるオリジンのリソースと通信する場合に制限される
- 目的は他オリジンに悪影響を与えないようにするため
- 自身のオリジンから別のオリジンへアクセスするのを許可する (クロスオリジン)
- Origin オリジンとは??
- 『 スキーム + ホスト + ポート番号 』
- https://domain-a.com:8000 の場合だと
- スキーム: https
- ホスト: domain-a.com
- ポート番号: 8000
- https://domain-a.com:8000 の場合だと
- 『 スキーム + ホスト + ポート番号 』
- クロスオリジンリクエスト例
https://domain-a.com:8000
-->https://domain-a.com:8080
( ポート番号が異なる )https://domain-a.com:8000
-->https://domain-b.com:8000
( ホストが異なる)
Ref) Cross-Origin Resource Sharing (CORS) - HTTP | MDN
コード
■ ディレクトリ構成
├── README.md ├── TEST_Client │ └── cors │ ├── index.php │ └── script.js ├── api/ (省略) ├── conf │ └── config.go ├── docker │ ├── mysql │ └── redis ├── docker-compose.yml ├── go.mod ├── go.sum ├── handler │ ├── auth.go │ └── top.go ├── main.go ├── model │ ├── crypto.go │ ├── db.go │ ├── stock.go │ └── user.go ├── staticcheck.conf └── view ├── login.html ├── mypage.html ├── signup.html └── top.html
- 参考
// CORS // e.Use(middleware.CORS()) e.Use(middleware.CORSWithConfig( middleware.CORSConfig{ // Method AllowMethods: []string{ http.MethodGet, http.MethodPut, http.MethodPost, http.MethodDelete, }, // Header AllowHeaders: []string{ echo.HeaderOrigin, }, // Origin /* AllowOrigins: []string{ "http://localhost:8080", "http://localhost:9999", },*/ }))
- main.go (全体)
package main import ( "io" "net/http" "text/template" "github.com/gorilla/sessions" "github.com/labstack/echo-contrib/session" "github.com/labstack/echo/v4" "github.com/labstack/echo/v4/middleware" "github.com/yhidetoshi/apiEchoGAE-local/api" "github.com/yhidetoshi/apiEchoGAE-local/conf" "github.com/yhidetoshi/apiEchoGAE-local/handler" ) var e = createMux() func createMux() *echo.Echo { e := echo.New() return e } type TemplateRender struct { templates *template.Template } func (t *TemplateRender) Render(w io.Writer, name string, data interface{}, c echo.Context) error { return t.templates.ExecuteTemplate(w, name, data) } func main() { // Echoインスタンス作成 // http.Handle("/", e) e.Use(middleware.Logger()) e.Use(middleware.Recover()) e.Use(middleware.Gzip()) // CORS // e.Use(middleware.CORS()) e.Use(middleware.CORSWithConfig( middleware.CORSConfig{ // Method AllowMethods: []string{ http.MethodGet, http.MethodPut, http.MethodPost, http.MethodDelete, }, // Header AllowHeaders: []string{ echo.HeaderOrigin, }, // Origin /* AllowOrigins: []string{ "http://localhost:8080", "http://localhost:9999", },*/ })) cGmo := api.ClientCryptoGMO{} cGmo.NewClientCryptoGMO() cCc := api.ClientCryptoCoincheck{} cCc.NewClientCryptoCoincheck() // Template renderer := &TemplateRender{ templates: template.Must(template.ParseGlob("view/*.html")), } e.Renderer = renderer // セッション e.Use(session.Middleware(sessions.NewCookieStore([]byte(conf.SIGNING_KEY)))) // ルーティング // // ヘルスチェック apiG := e.Group("/api") apiG.GET("/healthcheck", api.Healthcheck) // /api/healthcheck (/apiを省略する形になる) // 貴金属の価格を取得 apiG.GET("/metal", api.FetchMetal) // ISINコードを引数に基準価格を取得 apiG.GET("/investment-trust/:isin", api.FetchInvestTrust) // 仮想通貨の価格を取得 apiG.GET("/crypto/gmo", cGmo.FetchCryptoGMO) apiG.GET("/crypto/coincheck", cCc.FetchCryptoCoincheck) // HTMLページ e.GET("/", handler.ShowTopHTML) e.GET("/signup", handler.ShowSignUpHTML) e.POST("/signup", handler.SignUp) e.GET("/login", handler.ShowLoginHTML) e.GET("/mypage", handler.ShowMyPageHTML) e.POST("/login", handler.Login) e.POST("/logout", handler.Logout) e.GET("/restricted", handler.ShowRestrictedPage) apiG.Use(middleware.JWTWithConfig(handler.JWTConfig)) apiG.GET("/private", handler.ShowData) e.Start(":8080") }
動作確認
CORSを検証するための準備
- phpとjsでクライアントを用意する。(以下の記事を参考にさせていただきました 🙏)
- CORS を分かってないから動くコード書いて理解する - Qiita
├── TEST_Client │ └── cors │ ├── index.php │ └── script.js
- index.php
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <script src="./script.js"></script> </head> <body> CORS Test Page </body> </html>
- script.js
var xhr = new XMLHttpRequest() var url = 'http://localhost:8080/' const handler = () => { // コンソールに出力 console.log(xhr.responseText) } const getRequest = () => { xhr.open('GET', url) xhr.onloadend = handler xhr.send() } document.addEventListener('DOMContentLoaded', () => { getRequest() })
- クライアントを起動 ( Portは任意 )
$ php -S localhost:9999
検証
- クライアント( php + js )
localhost:9999
。 Echoをlocalhost:8080
で起動する。 localhost:9999
-->localhost:8080
でクロスオリジンリクエストを発生させる。
■ CORS設定をしない場合
Access to XMLHttpRequest at 'http://localhost:8080/' from origin 'http://localhost:9999' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
■ AllowHeaders を追加
AllowHeaders: []string{
echo.HeaderOrigin,
},
■ AllowMethods を追加
AllowMethods: []string{
http.MethodGet,
http.MethodPut,
http.MethodPost,
http.MethodDelete,
},
■ AllowOrigins を追加
AllowOrigins: []string{ "http://localhost:8080", "http://localhost:9999", },
→ それぞれ blocked by CORS policy: No 'Access-Control-Allow-Origin' header
のエラーを解消することができた。