gRPC-Webのメモ
ただの使ってみた記事です。
ScalaでAkka gRPCを利用してgRPCサーバを動かし、Envoy Proxyを介してgRPC-Webを触れるようにしたので、gRPC-Webのクライアントを構築してみた。
gRPC-Web クライアント
grpc.io この辺りのチュートリアルを見ながらなぞっただけなのでクライアント側は特に変わったことはしていない。 2個前くらいの記事に置いといたToDoサービス用のprotoファイルを使ってコードを生成した。
とりあえずpackage.jsonに以下の記述を追加してnpm経由で叩けるようにはしたが
"scripts": { "gen-todo": "protoc -I /path/to/protobuf --js_out=import_style=commonjs:service --grpc-web_out=import_style=commonjs,mode=grpcwebtext:service todo.proto" }
いくつか設定値があるようなので、requireを使えるようにcommonjsにしたり、お試し用途なのでbinaryではなくplain textを扱う mode=grpcwebtext
を指定した。
生成されたファイルからの依存があるので、grpc-web
と google-protobuf
dependenciesに追加する必要がある。
あとは生成したファイルを素直に使い、Clientを初期化してRequestを渡してrpcメソッドを叩けば動く。 Repositoryとかインフラ層のレイヤーからここに依存させてメソッドを叩くだけで良いので、やれHTTP通信ライブラリ何にしようとか悩まなくて良くもなるのでかなり楽かもしれない。
ただ、ドキュメントで以下の記述になっているようにコールバックを渡す形式なのが困る。
echoService.echo(request, {}, function(err, response) { // ... });
ので、RepositoryとかでPromise化してあげる必要がありそう。 というか外部との通信レイヤーとのインターフェースはすでにPromiseなはずなので、インターフェースを保ってあげるだけで良いんだな。
という形でクライアントサイドは非常に楽だったのだが、CORSの設定周りでドハマリして時間がかかった。
CORS
結局はEnvoy Proxyの設定の話でしか無いのだけど。
- クライアントサイドからEnvoyにリクエストしたらCORSエラーが出た
- EnvoyにCORSを許可する設定を入れたがうまく動かなかった
- Akka gRPCのgRPC-Web対応のハンドラを試してみたがうまく動かなかった
- EnvoyのCORS設定をし直して動いた
という流れで解決したが、時間がかかった。
最終的にEnvoyのCORS周りの設定値は以下のようになった。
route_config: name: local_route virtual_hosts: - name: local_service domains: - "*" cors: allow_origin_string_match: - prefix: "*" allow_methods: "OPTIONS, GET, PUT, DELETE, POST" allow_headers: keep-alive,user-agent,cache-control,content-type,content-transfer-encoding,x-accept-content-transfer-encoding,x-accept-response-streaming,x-user-agent,x-grpc-web expose_headers: grpc-status,grpc-message routes: - match: prefix: "/" route: cluster: todo_service http_filters: - name: envoy.filters.http.cors - name: envoy.filters.http.grpc_web - name: envoy.filters.http.router
もともと match
の箇所にgrpc
の設定値を入れていたのだが、あってはいけなかったらしい。
その設定値があるとOPTIONSメソッドでのリクエストがgrpcリクエストではないため正常にEnvoyでハンドリングされず、404だったり415だったりのエラーになってしまってgrpcリクエストが失敗してしまうという原因だった。
時間がかかる原因にもなったのだが、EvansのgRPC-Webオプション(--web
)をつけるとInputting Canceledなど原因不明なエラーに遭遇し、これがAkka gRPCのエラーなのかEnvoyのものなのかなど調べる必要がでてしまったこともある。
結局EvansのwebオプションをつけるとgRPC-Webのドキュメントからリンクされてるオフィシャルのプロジェクトですら動かなかったので、Evans側の問題なのだろうということにした… 追えればEvansのコード追ってみたい。
あと、gRPC-Web自体がどう動くものなのか分かっていなかったので少し調べたが、以下の記事が参考になった。
https://blog.envoyproxy.io/envoy-and-grpc-web-a-fresh-new-alternative-to-rest-6504ce7eb880
ブラウザからgRPCサーバに対してのgRPCリクエストは送れないので、間に中継役が必要になり、それがEnvoyだということ。
ブラウザからEnvoyに対してはHTTPリクエストを送信し、Envoyから裏側のgRPCサーバに対してHTTP/2の通信をしてくれるということ、などが解説されていて勉強になった。
gRPCサーバ、クライアントの構築が完了して、どちらもこれ以降の実装イメージが湧いたのでOKとする。