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


14

Après avoir mis à niveau vers la nouvelle 2.2.0.RELEASEversion de Spring Boot, certains de mes tests ont échoué. Il semble que le MediaType.APPLICATION_JSON_UTF8soit obsolète et qu'il ne soit plus renvoyé comme type de contenu par défaut à partir des méthodes de 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 illustré ci-dessous

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

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

Mais maintenant, lors de la comparaison contentavec 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 .getContentAsString()méthode 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 contenten encodage UTF-8?

Réponses:


7

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

.getContentAsString(StandardCharsets.UTF_8) - bon mais dans n'importe quelle réponse serait rempli 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));
    }
...

C'était la solution la plus simple recommandée ici!
Times

tu m'as sauvé la journée!
Filomat


2

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.


Avec cette solution, je devrais configurer le mockMvc dans chaque classe de test. Cela peut être assez fastidieux pour de nombreuses classes de test!
Times

0

Selon cette demande de traction des développeurs de printemps, l'en-tête UTF-8 n'est plus nécessaire 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 tout devrait bien se passer.


Je pense que vous ne comprenez pas le problème. Je vous suggère de lire toute la question, puis de réévaluer, si votre réponse apporte une valeur. Mon application fonctionne parfaitement bien, le problème est lié aux tests.
Times

J'ai relu toute la question et réévalué ma réponse, la réponse est toujours la même. Dans votre question, vous n'expliquez pas pourquoi l'en-tête est obsolète, j'ai enrichi votre question avec mon message. Je vous suggère de lire le PR auquel j'ai lié, afin que vous compreniez pourquoi l'en-tête est obsolète. Si vous comprenez pourquoi, vous souhaiterez peut-être envisager de modifier votre test car votre test teste le comportement par défaut dans Spring 2.1.X, mais il ne teste pas correctement le comportement dans Spring 2.2.X. Le comportement de Spring a changé, votre test devrait changer en conséquence si vous acceptez le nouveau comportement de Spring.
scre_www

Vous n'êtes pas très cohérent ici. Dans votre réponse, vous dites "[...] au lieu d'essayer de corriger votre test". Dans votre commentaire, vous dites "[...] votre test devrait changer en conséquence si vous acceptez le nouveau comportement Spring".
Times

Chaque programmeur fait face à des valeurs obsolètes de temps en temps. Quand quelque chose est obsolète, vous pouvez le réparer d'une manière ou d'une autre sans chercher pourquoi il est devenu obsolète en premier lieu. Cette approche semble être la façon dont vous gérez ce problème. Maintenant, je vous suggère de regarder plus loin et de rechercher pourquoi il est devenu obsolète. Si vous comprenez cela, vous pouvez prendre une meilleure décision sur la suite des choses. Dans votre question, il n'y a rien sur la raison pour laquelle vous nous dites seulement que votre test échoue en raison d'une valeur déconseillée qui est une mauvaise recherche. J'ai enrichi la question avec quelques recherches que vous n'avez pas faites ET voté le Q.
scre_www

0

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

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 codé en UTF-8 .)

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

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.