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.