sourcecode

MockMvc는 더 이상 스프링 부트 2.2.0에서 UTF-8 문자를 처리하지 않습니다.풀어주다

codebag 2023. 3. 19. 18:09
반응형

MockMvc는 더 이상 스프링 부트 2.2.0에서 UTF-8 문자를 처리하지 않습니다.풀어주다

새로 출시된 제품으로 업그레이드한 후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."}]

어떻게 하면 얻을 수 있나요?contentUTF-8 인코딩으로요?

네, 이것은 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()이 문제를 해결합니다.

스프링 5.2.0 버전 이후 기본 인코딩 문자는 UTF-8이 아닙니다.

UTF-8을 계속 사용하려면 MockMvc 결과의 ServletResponse에서 UTF-8을 설정해야 합니다.디폴트 문자 인코딩을 UTF-8 로 설정하려면 , 셋업 방법으로 다음과 같이 합니다.

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

그런 다음 mockMvc 인스턴스를 사용하여 요청을 수행할 수 있습니다.

이게 도움이 됐으면 좋겠다.

Spring Boot 1.5.15를 사용하고 있습니다.릴리스되어 쓰기 테스트에서도 같은 문제가 발생하였습니다.

처음에 도움이 된 솔루션은 .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();
}

원래 동작을 복원하려면(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의 답변에 따라 다음 항목을 입력하여 모든 테스트에서 문자 인코딩을 덮어쓸 수 있습니다.MockMvcBuilderCustomizer「 」 「 」 、 「 」 。

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

MockMvc를 MockMvc를 이 될 수 .@AutoconfigureMockMvc.

스프링 개발자의 이 풀 요청에 따라 UTF-8 헤더는 더 이상 필요하지 않으므로 더 이상 사용되지 않습니다.응용 프로그램에서 UTF-8 헤더를 사용하는 경우 테스트를 수정하는 대신 해당 헤더를 응용 프로그램에서 제거하는 것이 좋습니다.Content-Type: application/json 헤더를 사용하고 있는지 확인하기만 하면 됩니다.

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을 사용하여 인코딩해야 합니다).

관련 문제:JSON 응답용 MockMvc에서의 UTF-8의 부적절한 취급 · 이슈 #23622 · spring - projects / spring - framework

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>

언급URL : https://stackoverflow.com/questions/58525387/mockmvc-no-longer-handles-utf-8-characters-with-spring-boot-2-2-0-release

반응형