MockMvc больше не обрабатывает символы UTF-8 с Spring Boot 2.2.0.RELEASE


14

После обновления до недавно выпущенной 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."}]

Как я могу получить contentв кодировке UTF-8?

Ответы:


7

Да. Это проблема с 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));
    }
...

Это было самое простое решение, рекомендованное здесь!
Раз

ты спас мой день!
Филомат


2

Кодировка по умолчанию больше не является UTF-8, начиная с версии 5.2.0 spring.

Чтобы продолжить использование UTF-8, вы должны установить его в ServletResponse результата MockMvc. Чтобы установить кодировку символов по умолчанию UTF-8, сделайте что-то подобное в вашем методе настройки:

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

Затем вы можете использовать экземпляр mockMvc для выполнения вашего запроса.

Надеюсь, это поможет.


С этим решением мне пришлось бы настраивать mockMvc в каждом тестовом классе. Это может быть довольно утомительным для многих тестовых классов!
Раз

0

Согласно этому запросу от разработчиков пружин, заголовок UTF-8 больше не требуется, и поэтому он устарел. Если вы используете заголовок UTF-8 в своем приложении, вы можете рассмотреть возможность его удаления из приложения вместо того, чтобы пытаться исправить свой тест. Просто убедитесь, что вы используете заголовок Content-Type: application / json, и все будет в порядке.


Я думаю, что вы не понимаете проблему. Я предлагаю вам прочитать весь вопрос, а затем пересмотреть, если ваш ответ имеет какое-либо значение. Мое приложение работает отлично, проблема связана с тестами.
Время

Я снова прочитал весь вопрос и пересмотрел свой ответ, ответ остался прежним. В своем вопросе вы не объясняете, почему заголовок устарел, я обогатил ваш вопрос своим постом. Я предлагаю вам прочитать PR, на который я ссылался, чтобы вы поняли, почему заголовок устарел. Если вы понимаете причину, вы можете подумать об изменении своего теста, поскольку ваш тест проверяет поведение по умолчанию в Spring 2.1.X, но он не проверяет поведение в Spring 2.2.X правильно. Поведение Spring изменилось, ваш тест должен измениться соответственно, если вы примете новое поведение Spring.
scre_www

Вы не очень последовательны здесь. В своем ответе вы говорите «[...] вместо того, чтобы пытаться исправить свой тест». В своем комментарии вы говорите: «[...] ваш тест должен измениться соответствующим образом, если вы примете новое поведение Spring».
Раз

Каждый программист время от времени сталкивается с устаревшими значениями. Когда что-то устарело, вы можете как-то это исправить, не выясняя, почему это вообще устарело . Этот подход, кажется, является способом решения этой проблемы. Теперь я предлагаю вам посмотреть дальше и исследовать, почему это устарело. Если вы понимаете это, вы можете принять лучшее решение о том, что делать дальше. В вашем вопросе нет ничего о том, почему вы только говорите нам, что ваш тест не пройден из-за устаревшего значения, которое является плохим исследованием. Я обогатил этот вопрос некоторыми исследованиями, которые вы не проводили, и проголосовал за Q.
scre_www

0

Я использую 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();
}

0

Дополнительные настройки для 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 .)

связанная с этим проблема: неправильная обработка UTF-8 в MockMvc для ответа JSON · проблема № 23622 · spring-projects / spring-framework

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.