Flutter从服务器获取的日语字符解码错误。

47

我正在使用Flutter构建移动应用。

我需要从服务器获取一个包含日语文本的json文件。返回的json内容的一部分如下:

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

在Postman或Chrome上尝试相同的请求会得到预期的结果(输出中的日文字符会被正确呈现)。

但是当使用以下Dart代码片段获取数据时:

  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);

print语句在logcat中的结果为

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

请注意,仅日文字(content键的值)会变成乱码,其他非日语值仍然可以正确显示。

两点需要注意:

  1. 如果我尝试通过Text()在我的应用程序中显示这些日文文本,则会呈现相同的乱码,因此这不是Android Studio的logcat的错误。
  2. 如果我使用Text('put some Japanese text here directly')(例如:Text('睡眠')),Flutter将正确显示它,因此不是Text小部件弄乱了日语字符。

2
可能是与 https://github.com/dart-lang/http/issues/175 相同的问题。 - Günter Zöchbauer
2个回答

121

如果您查看Postman,可能会发现服务器发送的Content-Type HTTP标头缺少encoding标记。这会导致Dart http客户端将正文解码为Latin-1而不是utf-8。有一个简单的解决方法:

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

感谢提供有关编码标签的额外信息。那很有帮助!只是为了确保我理解正确,当我使用Postman时,会有9个响应头,其中2个是Content-Encoding →gzipcontent-type →application/json。所以我猜测encoding标签没有丢失,但它的值是错误的(例如,该值应该是'utf-8'而不是'gzip')。是这样吗? - Tran Triet
8
实际上,只需要修改Content-Type头部信息。使用Content-Type: application/json,Dart将会假定为Latin-1编码。而使用Content-Type: application/json; charset=utf-8,Dart将使用指定的字符集解码字节(response.bodyBytes)到字符(response.body)。解决方法是自行解码字节,因为你知道字符集是utf-8。 - Richard Heap
@RichardHeap,我可以请您看一下这里关于Flutter的问题吗:https://stackoverflow.com/questions/60565658/fluter-image-picker-package-show-images-one-after-another-with-delete-action? - Istiaque Ahmed
根据https://www.ietf.org/rfc/rfc4627.txt,这种行为(从技术上讲)不是错误的吗?它在第3节中指出:“JSON文本应该使用Unicode编码。默认编码是UTF-8。” 因此,如果Content-Type是“application/json”(没有charset=utf-8),http不应该自动使用utf-8解码正文吗? - pablete
@pablete 这只是默认值 - 它可以是UTF-16BE等。此外,您不希望http为特定内容类型实现特殊情况。 - Richard Heap
@RichardHeap 如果要应用任何转换,我希望http实现正确的编码。对于'application/json'来说,正确的编码是毫无歧义的,因此应该使用它。同时,请查看此问题(双方都有很多讨论):https://github.com/dart-lang/http/issues/175 - pablete

7

非常简单! 不要使用response.body,而应该使用utf8.decode(response.bodyBytes)


2022年就像魔法一样运作。 - Elmar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接