🚨

Flutter(Dio)でAPI叩いたら464ステータスが返ってきた

2022/06/03に公開

464ステータス is 何

ロードバランサーは、ターゲットグループプロトコルのバージョン構成と互換性のない着信リクエストプロトコルを受信しました。

考えられる原因:

リクエストプロトコルは HTTP/1.1 であるが、ターゲットグループのプロトコルバージョンが gRPC または HTTP/2 である。

リクエストプロトコルは gRPC であるが、ターゲットグループのプロトコルバージョンが HTTP/1.1 である。

リクエストプロトコルは HTTP/2 であり、リクエストは POST ではないが、ターゲットグループのプロトコルバージョンが gRPC である。

https://docs.aws.amazon.com/ja_jp/elasticloadbalancing/latest/application/load-balancer-troubleshooting.html

🥺?

ポストマン(デスクトップアプリ)でも464が返されるけど、
Chrome直叩き、Talend APIなどブラウザ経由するとAPIの値が返ってくる模様…

ちょっと調べてstackoverflowで以下のやり取りを見つける。
https://stackoverflow.com/questions/65233710/fetch-in-node-receiving-status-code-464-but-working-in-browser

対応策

今回はFlutter側で対応しました!
(stackoverflowではALBの設定をいじって解消したようです。)

まずdioでhttp2を利用できるようプラグインを追加

pubspec.yaml
dependencies:
  flutter:
    sdk: flutter
  flutter_localizations:
    sdk: flutter
  dio: ^4.0.6
  dio_http2_adapter: ^2.0.0 // これを追加
  略

https://pub.dev/packages/dio_http2_adapter

後はDioのオプションに追加するだけ!

    final dio = Dio()
      ..options = BaseOptions(
        headers: {
          "Content-Type": "application/json",
        },
        baseUrl: config.apiBaseUrl,
        receiveTimeout: 5000,
        connectTimeout: 5000,
      )
+     ..httpClientAdapter = Http2Adapter(
+       ConnectionManager(idleTimeout: 10000),
+     );

これでうまく行きました🙆‍♀️

ところがどっこい別で謎のエラーが出る。

Stream error: Stream was terminated by peer〜と謎のエラーが発生。
とりあえず調べてたらこの辺りが匂ってきた↓
https://github.com/flutterchina/dio/issues/486
https://github.com/dart-lang/http2/issues/49

こちらはサーバ側の方で対策を行なって頂き事なきを得ました🥺
いやはや/2.0に翻弄されてしまった…

おまけ

curlでプロトコルを調べる方法 (-vを付けてエンドポイントを叩くだけ)

curl -v http://127.0.0.1:3000/api_endpoint
*   Trying 127.0.0.1:3000...
* Connected to 127.0.0.1 (127.0.0.1) port 3000 (#0)
> GET /api_endpoint HTTP/1.1 ←http2だと「HTTP/2」になる。
> Host: 127.0.0.1:3000
> User-Agent: curl/7.79.1
> Accept: */*

Discussion