1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Flutter on the web & Connect-goで詰まった話

Last updated at Posted at 2025-05-28

まえがき

もともとgRPCだったプロジェクトを、Flutter webに対応させるためにConnectRPCに乗り換えた際につまった話。

バージョン
go v1.2.4
flutter_sdk v3.24.3
Connect-dart v0.3.0

ConnectRPCについて

ConnectRPCとは...

Connect is a family of libraries for building browser and gRPC-compatible HTTP APIs: you write a short Protocol Buffer schema and implement your application logic, and Connect generates code to handle marshaling, routing, compression, and content type negotiation. It also generates an idiomatic, type-safe client in any supported language.

要約すると...
gRPC互換のHTTP APIを構築するためのライブラリ群で、proto書いて自動生成で型安全なコードも生成してくれるやつ(詳しくは自分で調べてください)

詰まったところ

gRPCで実装していたコードをConnectに置き換えた後、Flutter webd通信をすると

[invalid_argument] protocol error: promised 246 bytes, received 331
at Object.throw_ [as throw]

こんな感じでエラーを吐く。

ライブラリの当該箇所の実装を見ると

packages/connect/lib/src/protocol/sink.dart
if (expLength != null && actLength > expLength) {
  throw ConnectException(
    Code.invalidArgument,
    'protocol error: promised $expLength bytes, received $actLength',
  );
}

つまり、プロトコルが本来受け取る予定だったデータ量(246バイト)と、実際に届いたデータ量(331バイト)が一致していないときにエラーを吐く。

このとき、実際受け取るデータ量が多いということは、本来受け取る予定だったデータ量というのは圧縮された値でありそう。

原因: ブラウザが自動で gzip を展開する

  • サーバーは Content-Encoding: gzip を付けてレスポンスを返す
  • ブラウザ (Fetch / XMLHttpRequest) はこのヘッダーを見て自動で解凍する
  • Connect の 5 バイトエンベロープには 圧縮後サイズ が入る
  • Dart 側で合計されるのは 解凍後のサイズ
    そのため、宣言サイズ 246 バイトと伸長後 331 バイトが一致せず、invalid_argument 例外が発生する。

暫定の解決策

サーバー側のハンドラーの圧縮を無効化する

main.go
p, h = hogehogeconnect.NewFugaServiceHandler(
    &hogefuga.Server{}, 
    connect.WithCompressMinBytes(math.MaxInt)
)

WithCompressMinBytes(math.MaxInt)を追加してgzipを無効化する。

まとめ

  • Flutter Web ではブラウザが Content-Encoding: gzip を自動展開

  • エンベロープのサイズは「圧縮後バイト数」なので、展開後と一致しなくなる

  • 暫定策として圧縮を無効化するか、HTTP の Content-Encoding を外すことで解決

ライブラリ側(Connect-dart のブラウザ版)が、このパターンに未対応なのが直接原因

Connect プロトコル自体は本来 Connect-Content-Encoding ヘッダー(または Streaming-Content-Encoding)を使い、ブラウザに解凍させない設計だが、Go 実装は歴史的理由で HTTP 標準の Content-Encoding も出す ため、ズレが発生する

参考文献

https://connectrpc.com/docs/protocol/
https://connectrpc.com/docs/go/serialization-and-compression/

1
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?