从Spring Boot 2.2开始,Content-Type: application/json不再附带charset=UTF-8
总结
-
- Spring Boot 2.2 から @RestController にて JSON を返す際の HTTP レスポンスヘッダで Content-Type: application/json になる (charset=UTF-8が付かない)
- Spring Boot 2.1 では @RestController にて JSON を返す際の HTTP レスポンスヘッダで Content-Type: application/json;charset=UTF-8 になる
验证代码
以下是我的应用程序的主要源代码:src/main/java/com/example/MyApp.java。
package com.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.nio.charset.StandardCharsets;
import java.util.Map;
@SpringBootApplication
@RestController
public class MyApp {
public static void main(String[] args) {
SpringApplication.run(MyApp.class, args);
}
// Spring Boot 2.2 から Content-Type に charset=UTF-8 が付かない
@GetMapping("/foo")
public Map foo() {
return Map.of("message", "こんにちわ、世界。");
}
// HTTP レスポンスヘッダを自前で指定することは可能
@GetMapping("/bar")
public ResponseEntity bar() {
Map body = Map.of("message", "こんにちわ、世界。");
// Content-Type: application/json;charset=UTF-8 を指定
HttpHeaders headers = new HttpHeaders();
headers.setContentType(new MediaType(MediaType.APPLICATION_JSON, StandardCharsets.UTF_8));
return new ResponseEntity<Map>(body, headers, HttpStatus.OK);
}
}
使用Gradle构建脚本的Spring Boot 2.1
将文件名保存为2.1-build.gradle。
plugins {
id 'org.springframework.boot' version '2.1.15.RELEASE'
id 'io.spring.dependency-management' version '1.0.9.RELEASE'
id 'java'
}
group = 'com.example'
version = '0.0.1'
sourceCompatibility = '11'
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
}
Spring Boot 2.2 的 Gradle 构建脚本
请将文件名保存为2.2-build.gradle。
plugins {
id 'org.springframework.boot' version '2.2.8.RELEASE'
id 'io.spring.dependency-management' version '1.0.9.RELEASE'
id 'java'
}
group = 'com.example'
version = '0.0.1'
sourceCompatibility = '11'
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
}
验证
- 実行環境: macOS Catalina + Java 11 (AdoptOpenJDK 11.0.7)
Spring Boot 2.1 春季启动框架版本2.1
使用Spring Boot 2.1构建和启动服务器。
$ gradle -b 2.1-build.gradle bootRun
用另一个控制台通过curl访问。
HTTP响应头中含有Content-Type: application/json;charset=UTF-8,并附带了charset=UTF-8。
$ curl --include http://localhost:8080/foo
HTTP/1.1 200
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Tue, 16 Jun 2020 12:15:23 GMT
{"message":"こんにちわ、世界。"}
$ curl --include http://localhost:8080/bar
HTTP/1.1 200
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Tue, 16 Jun 2020 12:15:27 GMT
{"message":"こんにちわ、世界。"}
Spring Boot 2.2
Spring Boot 2.2
使用Spring Boot 2.2构建并启动服务器。
$ gradle -b 2.2-build.gradle bootRun
从其他控制台使用curl进行访问。
HTTP响应头中包含Content-Type: application/json,而不附带charset=UTF-8。
$ curl --include http://localhost:8080/foo
HTTP/1.1 200
Content-Type: application/json
Transfer-Encoding: chunked
Date: Tue, 16 Jun 2020 12:16:24 GMT
{"message":"こんにちわ、世界。"}
如果在自己的HTTP响应头中添加了charset=UTF-8,则会保留它。
$ curl --include http://localhost:8080/bar
HTTP/1.1 200
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Tue, 16 Jun 2020 12:16:27 GMT
{"message":"こんにちわ、世界。"}
JSON的规范
JSON必须使用UTF-8进行编码。
最新的JSON规范「RFC 8259」和「ECMA-404第二版」已经发布。UTF-8编码是必需的。
在RFC 8259更新的JSON规范中,要求将UTF-8作为字符编码。
Content-Type 被指定为 application/json,但没有定义字符集。
RFC 8259:JavaScript对像记法(JSON)数据交换格式
JSON文本的媒体类型是application/json。
注意:此注册中没有定义”charset”参数。添加该参数对符合规范的接收方没有任何影响。
MediaType.APPLICATION_JSON_UTF8 不再被推荐使用
Spring Boot 2.1依赖的Spring Framework 5.1允许使用MediaType.APPLICATION_JSON_UTF8。
媒体类型(Spring Framework 5.1.16.RELEASE API)- Javadoc 日本語訳
public static final MediaType APPLICATION_JSON_UTF8
这是一个公共常量媒体类型,用于设置application/json;charset=UTF-8,该APPLICATION_JSON变量应用于JSON内容类型的设置。尽管在RFC7159中指定了“该注册未定义字符集参数”,但某些浏览器需要正确解释UTF-8特殊字符。
Spring Boot 2.2所依赖的Spring Framework 5.2版本已将MediaType.APPLICATION_JSON_UTF8标记为弃用(@Deprecated)。
媒体类型(Spring Framework 5.2.7.RELEASE API)- Javadoc 日本語翻訳
请勿使用 APPLICATION_JSON_UTF8。
像 Chrome 这样的主流浏览器在规范上符合要求,能够正确解释 UTF-8 的特殊字符,而无需 charset=UTF-8 参数。因此,我们建议在5.2版本中使用 APPLICATION_JSON。
废弃 MediaType.APPLICATION_JSON_UTF8,推荐使用 APPLICATION_JSON · Issue #22788 · spring-projects/spring-framework · GitHub
RFC 8259已经淘汰了RFC 7159,其中提到:“对于此注册,没有定义’charset’参数。为其添加参数对兼容的接收方没有任何影响。”(在第11节末尾)
…并且浏览器已经修复了它们的代码。因此最好是明确文本并废弃这个常量。
看下列資料
-
- Deprecate MediaType.APPLICATION_JSON_UTF8 in favor of APPLICATION_JSON · Issue #22788 · spring-projects/spring-framework · GitHub
-
- Spring MVCのコントローラでの戻り値いろいろ – Qiita
-
- Spring 5でレスポンスにヘッダを設定する方法
-
- How to make spring boot default to application/json;charset=utf-8 instead of application/json;charset=iso-8859-1 – Stack Overflow
-
- 438464 – json displayed with wrong encoding (i.e. not unicode) – chromium
- Media Types (Internet Assigned Numbers Authority)