升级到新发布的
2.2.0.RELEASE
版本的 Spring Boot 后,我的一些测试失败了。看来 MediaType.APPLICATION_JSON_UTF8
已被弃用,并且不再作为默认内容类型从未显式指定内容类型的控制器方法返回。
测试代码如下
String content = mockMvc.perform(get("/some-api")
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8))
.andReturn()
.getResponse()
.getContentAsString();
突然不再工作,因为内容类型不匹配,如下所示
java.lang.AssertionError: Content type
Expected :application/json;charset=UTF-8
Actual :application/json
将代码更改为
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
暂时解决了该问题。
但是现在,当将
content
与预期的序列化对象进行比较时,如果对象中有任何特殊字符,仍然不匹配。看来 .getContentAsString()
方法默认不再使用 UTF-8 字符编码。
java.lang.AssertionError: Response content expected:<[{"description":"Er hörte leise Schritte hinter sich."}]> but was:<[{"description":"Er hörte leise Schritte hinter sich."}]>
Expected :[{"description":"Er hörte leise Schritte hinter sich."}]
Actual :[{"description":"Er hörte leise Schritte hinter sich."}]
如何获得UTF-8编码的
content
?
是的。这是 2.2.0 spring-boot 的问题。他们设置了默认字符集编码的弃用。
.getContentAsString(StandardCharsets.UTF_8)
- 很好,但在任何响应中都会默认填充 ISO 8859-1。
在我的项目中,我更新了当前创建的转换器:
@Configuration
public class SpringConfig implements WebMvcConfigurer {
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.stream()
.filter(converter -> converter instanceof MappingJackson2HttpMessageConverter)
.findFirst()
.ifPresent(converter -> ((MappingJackson2HttpMessageConverter) converter).setDefaultCharset(UTF_8));
}
...
使用
.getContentAsString(StandardCharsets.UTF_8)
代替 .getContentAsString()
可以解决问题。
从spring 5.2.0版本开始默认编码字符不再是UTF-8。
要继续使用UTF-8,必须在MockMvc结果的ServletResponse中设置它。 要将默认字符编码设置为 UTF-8,请在设置方法中执行以下操作:
@Before
public void setUp() {
mockMvc = webAppContextSetup(wac).addFilter(((request, response, chain) -> {
response.setCharacterEncoding("UTF-8");
chain.doFilter(request, response);
})).build();
}
然后你可以使用mockMvc实例来执行你的请求。
希望这有帮助。
按照 black4bird 的答案,您可以通过在测试 Spring 上下文中放置以下
MockMvcBuilderCustomizer
实现来覆盖所有测试的字符编码:
@Component
class MockMvcCharacterEncodingCustomizer implements MockMvcBuilderCustomizer {
@Override
public void customize(ConfigurableMockMvcBuilder<?> builder) {
builder.alwaysDo(result -> result.response.characterEncoding = "UTF-8");
}
}
如果您不想显式设置 MockMvc,而只需使用
@AutoconfigureMockMvc
,这可能会有所帮助。
我正在使用 Spring Boot 1.5.15.RELEASE,并且在编写测试时遇到了同样的问题。
第一个帮助我的解决方案是添加 .characterEncoding("UTF-8")) 像这样:
String content = mockMvc.perform(get("/some-api")
.contentType(MediaType.APPLICATION_JSON)
.characterEncoding("UTF-8"))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8))
.andReturn()
.getResponse()
.getContentAsString();
我在测试类中使用 StandaloneMockMvcBuilder,因此帮助我的第二个解决方案是创建一个过滤器,例如:
private static class Utf8Filter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
response.setCharacterEncoding(StandardCharsets.UTF_8.toString());
filterChain.doFilter(request, response);
}
}
然后将其添加到我的测试类中的standaloneSetup方法中,如下所示:
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
final SomeResource someResource = new SomeResource(someService);
this.restLankMockMvc = MockMvcBuilders.standaloneSetup(someResource)
.setCustomArgumentResolvers(pageableArgumentResolver)
.setControllerAdvice(exceptionTranslator)
.setConversionService(createFormattingConversionService())
.setMessageConverters(jacksonMessageConverter)
.addFilter(new Utf8Filter())
.build();
}
MockMvc 的额外设置,
.accept(MediaType.APPLICATION_JSON_UTF8_VALUE)
:
String content = mockMvc.perform(get("/some-api")
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andReturn()
.getResponse()
.getContentAsString();
我猜这个问题不是 Spring Boot 的问题,而是 MockMvc 特有的问题。 因此,解决方法必须仅应用于 MockMvc。 (JSON 必须使用 UTF-8 编码。)
相关问题:MockMvc 中 JSON 响应的 UTF-8 处理不正确 · Issue #23622 · spring-projects/spring-framework
@Configuration
public class MyWebConfig implements WebMvcConfigurer {
@Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
configurer.defaultContentType(MediaType.APPLICATION_JSON_UTF8);
}
...
但是,由于 APPLICATION_JSON_UTF8 已被弃用,并且 Spring 的目的不是包含该字符集,因此最好继续修改您的测试。 black4bird 的解决方案对我有用。
this 拉取请求,不再需要 UTF-8 标头,因此已弃用。如果您在应用程序中使用 UTF-8 标头,您可能会考虑将其从应用程序中删除,而不是尝试修复测试。只要确保您使用的是 Content-Type: application/json 标头,就应该没问题。
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<argLine>-Dfile.encoding=UTF-8</argLine>
</configuration>
</plugin>
@Autowired
private WebApplicationContext wac;
private MockMvc mockMvc;
@PostConstruct
public void init() {
mockMvc = MockMvcBuilders.webAppContextSetup(wac)
.defaultResponseCharacterEncoding(StandardCharsets.UTF_8)
.build();
}
https://stackoverflow.com/users/8369595/micha%c5%82-kaciuba 的答案(https://stackoverflow.com/a/69380914/246097 )我使用了以下代码:
@Component
class MockMvcCharacterEncodingCustomizer implements MockMvcBuilderCustomizer {
@Override
public void customize(ConfigurableMockMvcBuilder<?> builder) {
builder.alwaysDo(result -> result.getResponse().setDefaultCharacterEncoding("UTF-8"));
}
}
请注意,我使用了 setDefaultCharacterEncoding
,而不是
setCharacterEncoding
。这样,我就可以像往常一样继续收到
application/json
,并且不需要使用
.getContentAsString(StandardCharsets.UTF_8)
。希望有帮助。