web-dev-qa-db-fra.com

MockMvc ne gère plus les caractères UTF-8 avec Spring Boot 2.2.0.

Après avoir effectué la mise à niveau vers la nouvelle version 2.2.0.RELEASE De Spring Boot, certains de mes tests ont échoué. Il semble que le MediaType.APPLICATION_JSON_UTF8 A été déprécié et n'est plus renvoyé comme type de contenu par défaut à partir des méthodes du contrôleur qui ne spécifient pas le type de contenu explicitement.

Code de test comme

String content = mockMvc.perform(get("/some-api")
            .contentType(MediaType.APPLICATION_JSON))
            .andExpect(status().isOk())
            .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8))
            .andReturn()
            .getResponse()
            .getContentAsString();

n'a soudainement plus fonctionné car le type de contenu n'était pas compatible comme indiqué ci-dessous

Java.lang.AssertionError: Content type 
Expected :application/json;charset=UTF-8
Actual   :application/json

Changer le code en .andExpect(content().contentType(MediaType.APPLICATION_JSON)) a résolu le problème pour l'instant.

Mais maintenant, lors de la comparaison de content à l'objet sérialisé attendu, il y a toujours un décalage s'il y a des caractères spéciaux dans l'objet. Il semble que la méthode .getContentAsString() n'utilise pas le codage de caractères UTF-8 par défaut (plus).

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."}]

Comment puis-je obtenir content en encodage UTF-8?

14
Times

Oui. C'est un problème de 2.2.0 spring-boot. Ils définissent la dépréciation pour le codage par défaut du jeu de caractères.

.getContentAsString(StandardCharsets.UTF_8) - bonne mais dans toute réponse serait remplie ISO 8859-1 par défaut.

Dans mon projet, j'ai mis à jour le convertisseur créé actuellement:

@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));
    }
...

L'utilisation de .getContentAsString(StandardCharsets.UTF_8) au lieu de .getContentAsString() résout le problème.

3
Times

Le caractère d'encodage par défaut n'est plus UTF-8 depuis la version 5.2.0 de spring.

Pour continuer à utiliser UTF-8, vous devez le définir dans la ServletResponse du résultat MockMvc. Pour définir le codage de caractères par défaut sur UTF-8, faites quelque chose comme ceci dans votre méthode de configuration:

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

Ensuite, vous pouvez utiliser l'instance mockMvc pour effectuer votre demande.

J'espère que cette aide.

2
black4bird

Paramètre supplémentaire à 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();

Ce problème n'est pas Spring Boot, mais spécifique à MockMvc, je suppose. Par conséquent, une solution de contournement doit être appliquée à MockMvc uniquement. ( JSON doit être encodé en UTF-8 .)

problème connexe: Mauvaise gestion UTF-8 dans MockMvc pour la réponse JSON · Numéro # 23622 · spring-projects/spring-framework

0
yukihane

Selon this pull request des développeurs de printemps, l'en-tête UTF-8 n'est plus requis et est donc obsolète. Si vous utilisez l'en-tête UTF-8 dans votre application, vous pouvez envisager de le supprimer de votre application au lieu d'essayer de corriger votre test. Assurez-vous simplement que vous utilisez l'en-tête Content-Type: application/json et ça devrait aller.

0
scre_www

J'utilise Spring Boot 1.5.15.RELEASE et j'ai rencontré le même problème lors de l'écriture de tests.

La première solution qui m'a aidé a été d'ajouter .characterEncoding ("UTF-8")) comme ceci:

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

J'utilise un StandaloneMockMvcBuilder dans ma classe de test, donc la deuxième solution qui m'a aidé était de créer un filtre, par exemple:

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

et l'ajouter plus tard à la méthode standaloneSetup dans ma classe de test comme ceci:

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