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. Вони встановлюють анулювання для кодування шаблонів за замовчуванням.

.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.

Щоб продовжувати використовувати 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, з яким я пов’язаний, щоб ви зрозуміли, чому заголовок застарілий. Якщо ви розумієте, чому ви, можливо, захочете змінити тест, оскільки ваш тест перевіряє поведінку за замовчуванням навесні 2.1.X, але він не перевіряє поведінку у Spring 2.2.X правильно. Поведінка Spring змінилася, і ваш тест повинен змінитися відповідно, якщо ви приймаєте нову поведінку Spring.
— scre_www

Ви тут не дуже послідовні. У своїй відповіді ви говорите "[...] замість того, щоб намагатися виправити тест". У своєму коментарі ви говорите: "[...] ваш тест повинен відповідно змінитися, якщо ви приймаєте нову поведінку весни".
— Часи

Кожен програміст стикається із застарілими значеннями час від часу. Коли щось застаріле, ви можете це якось виправити, не досліджуючи, чому воно зникло в першу чергу. Такий підхід здається способом вирішення цієї проблеми. Тепер я пропоную вам поглянути далі та вивчити, чому воно застаріло. Якщо ви це розумієте, ви можете прийняти краще рішення, що робити далі. У вашому запитанні немає нічого про те, чому ви лише кажете нам, що ваш тест провалюється через застаріле значення, яке є поганим дослідженням. Я збагатив це питання деякими дослідженнями, яких ви не робили, і схвалив питання 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);
    }
}

а пізніше додайте його до методу автономного налаштування в моєму тестовому класі так:

@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-Framework

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.