MockMvc 不再使用 Spring Boot 2.2.0.RELEASE 处理 UTF-8 字符
MockMvc no longer handles UTF-8 characters with Spring Boot 2.2.0.RELEASE
升级到 Spring 新发布的 2.2.0.RELEASE
版本后,我的一些测试失败了。 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
?
使用 .getContentAsString(StandardCharsets.UTF_8)
而不是 .getContentAsString()
可以解决问题。
是的。这是 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));
}
...
spring5.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 实例来执行您的请求。
希望对您有所帮助。
根据来自 spring 开发人员的 this 拉取请求,UTF-8 header 不再需要,因此已弃用。如果您在您的应用程序中使用 UTF-8 header,您可能会考虑将其从您的应用程序中删除,而不是尝试修复您的测试。只要确保您使用的是 Content-Type: application/json header 就可以了。
我正在使用 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 class,所以第二个帮助我的解决方案是创建一个过滤器,例如:
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);
}
}
然后将其添加到我的测试 class 中的 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 引导,而是 MockMvc 特定问题,我猜。
因此,必须仅将解决方法应用于 MockMvc。
(JSON must be encoded using UTF-8.)
要恢复原始行为 (Content-Type=application/json;charset=UTF-8) 并让您的测试按原样通过,您可以执行以下操作:
@Configuration
public class MyWebConfig implements WebMvcConfigurer {
@Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
configurer.defaultContentType(MediaType.APPLICATION_JSON_UTF8);
}
...
但是,由于 APPLICATION_JSON_UTF8 已被弃用并且 Spring 的意图是不包含字符集,因此最好继续修改您的测试。 black4bird 的解决方案对我有用。
根据 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 新发布的 2.2.0.RELEASE
版本后,我的一些测试失败了。 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
?
使用 .getContentAsString(StandardCharsets.UTF_8)
而不是 .getContentAsString()
可以解决问题。
是的。这是 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));
}
...
spring5.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 实例来执行您的请求。
希望对您有所帮助。
根据来自 spring 开发人员的 this 拉取请求,UTF-8 header 不再需要,因此已弃用。如果您在您的应用程序中使用 UTF-8 header,您可能会考虑将其从您的应用程序中删除,而不是尝试修复您的测试。只要确保您使用的是 Content-Type: application/json header 就可以了。
我正在使用 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 class,所以第二个帮助我的解决方案是创建一个过滤器,例如:
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);
}
}
然后将其添加到我的测试 class 中的 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 引导,而是 MockMvc 特定问题,我猜。 因此,必须仅将解决方法应用于 MockMvc。 (JSON must be encoded using UTF-8.)
要恢复原始行为 (Content-Type=application/json;charset=UTF-8) 并让您的测试按原样通过,您可以执行以下操作:
@Configuration
public class MyWebConfig implements WebMvcConfigurer {
@Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
configurer.defaultContentType(MediaType.APPLICATION_JSON_UTF8);
}
...
但是,由于 APPLICATION_JSON_UTF8 已被弃用并且 Spring 的意图是不包含字符集,因此最好继续修改您的测试。 black4bird 的解决方案对我有用。
根据 black4bird 的回答,您可以通过在测试 Spring 上下文中放置以下 MockMvcBuilderCustomizer
实现来覆盖所有测试的字符编码:
@Component
class MockMvcCharacterEncodingCustomizer implements MockMvcBuilderCustomizer {
@Override
public void customize(ConfigurableMockMvcBuilder<?> builder) {
builder.alwaysDo(result -> result.response.characterEncoding = "UTF-8");
}
}
如果您不想显式设置 MockMvc,而只使用 @AutoconfigureMockMvc
。