📶

connect-goとconnect-webでCORSが出た時の解決

2023/12/01に公開

gRPC互換の Connect について、チュートリアルを読みながら進めていたところ、CORSの解決でややハマってしまったので共有。

構成

  • server: Go
    • connectrpc.com/connectを使用
    • localhost:8080
  • client: Webからアクセス
    • Vitenpx vite で開発環境を建てる
    • 公式DocのGetting Started と同じように、 @buf/connectrpc_eliza.connectrpc_es @connectrpc/connect @connectrpc/connect-web を導入済み
    • localhost:5173 (viteのデフォルト)

解決策

雑に解決するなら、Go側で github.com/rs/corscors.AllowAll()をhandlerとして使う。

func main() {
	chat := &ChatServer{}
	mux := http.NewServeMux()
	path, handler := chatv1connect.NewChatServiceHandler(chat)
	mux.Handle(path, handler)

	// cors.Default()ではダメだった
	// corsHandler := cors.Default().Handler(h2c.NewHandler(mux, &http2.Server{}))
	
	// これ
	corsHandler := cors.AllowAll().Handler(h2c.NewHandler(mux, &http2.Server{}))
	
	http.ListenAndServe(
		"localhost:8080",
		corsHandler,
	)
}

解説

cors.Default() を使ったhandlerを使用するサンプルコードを幾つか見つけたのですが、これだとローカル環境で普通にCORSでひっかかりました。

rs/cors のデフォルト値を調べてみると、以下のように書いてあります。

AllowedMethods []string: A list of methods the client is allowed to use with cross-domain requests. Default value is simple methods (GET and POST).

一方、MDNにはこうもあります

ブラウザーが HTTP の OPTIONS リクエストメソッドを用いて、あらかじめリクエストの「プリフライト」 (サーバーから対応するメソッドの一覧を収集すること) を行い、サーバーの「認可」のもとに実際のリクエストを送信することを指示しています

恐らくrs/corsのデフォルト設定では、OPTIONSメソッドでプリフライトメッセージが弾かれているように見えます。

その辺の記事を参考にして rs/cors で全然解決しないが!?と1時間ぐらい悩んでました。やっぱ1次ソースをちゃんと確認しないとダメですね、反省です…

Discussion