Spring Boot MockMvc在Sping Boot 2.2.0.RELEASE中不再处理UTF-8字符

oknrviil  于 2023-01-20  发布在  Spring
关注(0)|答案(9)|浏览(145)

在我升级到新发布的2.2.0.RELEASE版本的Sping 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

o75abkj4

o75abkj41#

是的。这是2.2.0 Spring 启动时的问题。他们设置了默认字符集编码。
.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));
    }
...
4uqofj5v

4uqofj5v2#

使用.getContentAsString(StandardCharsets.UTF_8)代替.getContentAsString()可以解决此问题。

axzmvihb

axzmvihb3#

从5.2.0版本的spring开始,默认的编码字符不再是UTF-8。
要继续使用UTF-8,您必须在MockMvc结果的ServletResponse中设置它。要将默认字符编码设置为UTF-8,请在setup方法中执行以下操作:

@Before
public void setUp() {
   mockMvc = webAppContextSetup(wac).addFilter(((request, response, chain) -> {
                response.setCharacterEncoding("UTF-8");
                chain.doFilter(request, response);
            })).build();
}

然后您可以使用mockMvc示例来执行您的请求。
希望这能有所帮助。

r1wp621o

r1wp621o4#

我使用的是Sping 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();
}
0pizxfdo

0pizxfdo5#

要恢复原始行为(内容类型=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的意图是不包含字符集,因此最好继续修改您的测试。

egdjgwm8

egdjgwm86#

根据black4bird的回答,您可以通过在测试Spring上下文中放置以下MockMvcBuilderCustomizer实现来覆盖所有测试的字符编码:

@Component
class MockMvcCharacterEncodingCustomizer implements MockMvcBuilderCustomizer {
    @Override
    public void customize(ConfigurableMockMvcBuilder<?> builder) {
        builder.alwaysDo(result -> result.response.characterEncoding = "UTF-8");
    }
}

如果您不想显式地设置MockMvc,而只是使用@AutoconfigureMockMvc,那么这可能会有所帮助。

ifsvaxew

ifsvaxew7#

根据来自spring开发者的this pull请求,UTF-8头不再需要,因此不推荐使用。如果您在应用中使用UTF-8头,您可以考虑将其从应用中删除,而不是尝试修复测试。只需确保您使用的是Content-Type:application/json头文件,这样就可以了。

mv1qrgav

mv1qrgav8#

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

这个问题不是 Boot ,而是MockMvc特有的,我猜。所以,一个变通方案必须只应用于MockMvc。(JSON必须使用UTF-8编码。)
相关问题:Improper UTF-8 handling in MockMvc for JSON response · Issue #23622 · spring-projects/spring-framework

fae0ux8s

fae0ux8s9#

如果你使用的是maven,你可以使用maven-surefire-plugin并通过以下方式启用UTF-8编码:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <configuration>
        <argLine>-Dfile.encoding=UTF-8</argLine>
    </configuration>
</plugin>

相关问题