http | Dart package
A composable, multi-platform, Future-based API for HTTP requests.
https://pub.dev/packages/http
この記事では、Flutterでhttp通信の実装しているときに遭遇したエラー(Bad state: Cannot set the body fields of a Request with content-type “application/json”)の原因と解決方法を説明します。
以下の http というpackageを導入して実装しているときに発生したエラーです。(Flutterのデファクトスタンダードなんですかね?これ)
私の場合は、リクエストした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;
}
}
Bad state: Cannot set the body fields of a Request with content-type “application/json”
上記コードのrequestBody変数は Map
は 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