先说结论:charset 字段不对 application/json 类型的媒体内容生效,无论你怎么设置 charset ,框架都只会使用 utf-8 对字符串进行编码。charset 字段只用于 text/* 类型的媒体内容生效,也就是文本内容; application/*类型的数据在规范上属于二进制数据,不应受 charset 制约(框架和浏览器会直接忽略 charset )。
如果一定要用 GBK 传输数据,不要给 Spring 框架返回 Collection 例如 Map 类型,而是直接返回 String 类型。无论是返回哪种类型都不需要你手动进行编码了,框架会自动处理的。
// @
RestController 注解会自动将 map 转化为 json 并使用 utf-8 编码
// http 响应的媒体类型为 application/json
@
GetMapping("/hello-json")
public Map sayHelloByJSON() {
Map map = new HashMap<String, String>();
map.put("你好", "世界");
return map;
}
// 按照指定的编码传输文本数据
// http 响应的媒体类型为 text/*,具体类型要看框架的处理
@
GetMapping("/hello-gbk")
public String sayHelloByGbkString() {
return "你好,世界。";
}
-------
1. charset 字段对 text/*文本类型的影响,见:
https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Basics_of_HTTP/MIME_types"例如,对于主类型为 text 的任何 MIME 类型,可以添加可选的 charset 参数,以指定数据中的字符所使用的字符集"
2. JSON 文件(文本)应该使用 applicaiton/json 媒体类型进行描述,见:
https://www.iana.org/assignments/media-types/media-types.xhtml 。使用 text/*类型描述 json 文本被认为是违反规范的。
3. applicaiton/json 类型的数据不应受 charset 字段影响,见:
https://datatracker.ietf.org/doc/html/rfc6838#section-4.2.1该段有提到两点:
( 1 ). 包含“payload”的文本类型不应该使用 charset 字段,而应该由本身的规范指定(例如 xml 文件内部有编码集指定字段, 而 JSON 文件唯一指定为 utf-8 , 见
https://www.rfc-editor.org/rfc/rfc8259.html ),它们不应该受 charset 字段影响(直接忽略 charset,无论 charset 是否存在)
( 2 ). 如果一定要使用一种默认编码,使用“UTF-8”。
application/json 数据其实算是二进制数据,但是可以认为是上文所说"包含`payload`的文本类型".
------
嘛,应该挺多人对 json 数据胡乱进行处理的,乱码嘛,正常。
op 有兴趣的话可以看看这个讨论:
https://github.com/libwww-perl/HTTP-Message/pull/90讨论核心就是应该如何看待并处理 http 请求中的 json 类型"文本"(从浏览器和框架的角度)。对本问有一定的参考意义。