【Flutter】Cannot set the body fields of a Request with content-type… エラーの解決方法

2022/10/28
2020/07/13

はじめに

この記事では、Flutterでhttp通信の実装しているときに遭遇したエラー(Bad state: Cannot set the body fields of a Request with content-type “application/json”)の原因と解決方法を説明します。

以下の http というpackageを導入して実装しているときに発生したエラーです。(Flutterのデファクトスタンダードなんですかね?これ)

実行環境

  • macOS Catalina 10.15.5
  • package: http: ^0.12.1

原因と解決方法

私の場合は、リクエストしたAPIの仕様上 Content-Typeがapplication/jsonである必要があった ため、application/jsonでリクエストできるように対処した方法を紹介します。

原因

http.post() のbodyフィールドに渡すデータの型の影響で、リクエストヘッダーのContent-Typeが上書きできないものになっていたことが原因でした。

以下のコードでAPIコールした場合、タイトルの通りのエラーが発生しました。

エラーが発生したコード

import 'dart:io';
import 'package:http/http.dart' as http;
import 'dart:convert';
 
Future<bool> register(id, name) async {
  final requestBody = {
    'id': id,
    'name': name,
  };
 
  final response = await http.post(
    'https://hoge.com/register',
    headers: {
      HttpHeaders.contentTypeHeader: 'application/json',
      HttpHeaders.acceptHeader: 'application/json',
    },
    body: requestBody,
  );
 
  if (response.statusCode == 200) {
    return true;
  } else {
    return false;
  }
}
<span class="font-semibold">Bad state: Cannot set the body fields of a Request with content-type “application/json”</span>

Bad state: Cannot set the body fields of a Request with content-type “application/json”

上記コードのrequestBody変数は Map の変数であり、その型でリクエストした場合のContent-Type
は 
application/x-www-form-urlencoded となるようです。

http.post() のコードを覗くと、application/x-www-form-urlencoded の状態ではContent-Typeの上書きができないと記載されています。

Sends an HTTP POST request with the given headers and body to the given URL, which can be a [Uri] or a [String].

If [body] is a Map, it’s encoded as form fields using [encoding]. The content-type of the request will be set to "application/x-www-form-urlencoded"; this cannot be overridden.

http.postから

解決方法

requestBody変数に渡す型を json.encode() を使ってJSON形式のString型に変更すると、Content-Typeをapplication/jsonに上書きできるようになります。

タイトルのエラーが解決したコード

import 'dart:io';
import 'package:http/http.dart' as http;
import 'dart:convert';
 
Future<bool> register(id, name) async {
  final requestBody = json.encode({
    'id': id,
    'name': name,
  });
 
  final response = await http.post(
    'https://hoge.com/register',
    headers: {
      HttpHeaders.contentTypeHeader: 'application/json',
      HttpHeaders.acceptHeader: 'application/json',
    },
    body: requestBody,
  );
 
  if (response.statusCode == 200) {
    return true;
  } else {
    return false;
  }
}

ちなみに、Content-Typeをheaderに設定していない場合は、デフォルトのtext/plainが設定されます。

まとめ

今回は、Flutterのhttpというpackageを使ったAPIリクエストで発生したエラーの原因と対処法を紹介しました。

この問題はpackageのコードを読めば解決する問題なので、packageを使った時に発生するエラーの場合はコードを読んでみることが大事だとわかりました。

参考

https://stackoverflow.com/questions/27574740/http-post-request-with-json-content-type-in-dartio

Flutter の記事