Flutter fetched Japanese character from server decoded wrong

Tran Triet picture Tran Triet · Jul 16, 2018 · Viewed 12.4k times · Source

I am building a mobile app with Flutter.

I need to fetch a json file from server which includes Japanese text. A part of the returned json is:

{
     "id": "egsPu39L5bLhx3m21t1n",  
     "userId": "MCetEAeZviyYn5IMYjnp",  
     "userName": "巽 裕亮",  
     "content": "フルマラソン完走に対して2018/05/06のふりかえりを行いました!"
}

Trying the same request on postman or chrome gives the expected result (Japanese characters are rendered properly in the output).

But when the data is fetched with Dart by the following code snippet:

  import 'dart:convert';
  import 'package:http/http.dart' as http;

  //irrelevant parts have been omitted    
  final response = await http.get('SOME URL',headers: {'Content-Type': 'application/json'});
  final List<dynamic> responseJson = json.decode(response.body)
  print(responseJson);

The result of the print statement in logcat is

{
     id: egsPu39L5bLhx3m21t1n, 
     userId: MCetEAeZviyYn5IMYjnp, 
     userName: å·½ è£äº®, 
     content: ãã«ãã©ã½ã³å®èµ°ã«å¯¾ãã¦2018/05/06ã®ãµãããããè¡ãã¾ããï¼
}

Note that only the Japanese characters (value of the content key) is turns into gibberish, the other non-Japanese values are still displayed properly.

Two notices are:

  1. If I try to display this Japanese text in my app via Text(), the same gibberish is rendered, so it is not a fault of Android Studio's logcat.
  2. If I use Text('put some Japanese text here directly') (ex: Text('睡眠')), Flutter displays it correctly, so it is not the Text widget that messes up the Japanese characters.

Answer

Richard Heap picture Richard Heap · Jul 16, 2018

If you look in postman, you will probably see that the Content-Type http header sent by the server is missing the encoding tag. This causes the Dart http client to decode the body as Latin-1 instead of utf-8. There's a simple workaround:

http.Response response = await http.get('SOME URL',headers: {'Content-Type': 'application/json'});
List<dynamic> responseJson = json.decode(utf8.decode(response.bodyBytes));