MockMvc non gestisce più i caratteri UTF-8 con Spring Boot 2.2.0.RELEASE


14

Dopo aver eseguito l'aggiornamento alla 2.2.0.RELEASEversione appena rilasciata di Spring Boot, alcuni dei miei test fallirono. Sembra che MediaType.APPLICATION_JSON_UTF8sia stato deprecato e non venga più restituito come tipo di contenuto predefinito dai metodi del controller che non specificano esplicitamente il tipo di contenuto.

Codice di prova simile

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

improvvisamente non ha più funzionato poiché il tipo di contenuto non era corrispondente come mostrato di seguito

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

La modifica del codice per .andExpect(content().contentType(MediaType.APPLICATION_JSON))risolvere il problema per ora.

Ma ora quando si confronta contentcon l'oggetto serializzato previsto c'è ancora una discrepanza se ci sono caratteri speciali nell'oggetto. Sembra che il .getContentAsString()metodo non utilizzi la codifica dei caratteri UTF-8 per impostazione predefinita (non più).

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

Come posso ottenere la contentcodifica UTF-8?

Risposte:


7

Sì. Questo è un problema a partire dall'avvio a molla 2.2.0. Hanno impostato la deprecazione per la codifica del set di caratteri predefinito.

.getContentAsString(StandardCharsets.UTF_8) - buono ma in ogni risposta sarebbe popolato ISO 8859-1 per impostazione predefinita.

Nel mio progetto ho aggiornato il convertitore attualmente creato:

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

Questa è stata la soluzione più semplice consigliata qui!
Tempi

mi hai salvato la giornata!
Filomat,


2

Il carattere di codifica predefinito non è più UTF-8 dalla versione 5.2.0 di Spring.

Per continuare a utilizzare UTF-8, è necessario impostarlo nella risposta Servlet del risultato MockMvc. Per impostare la codifica dei caratteri predefinita su UTF-8, fai qualcosa del genere nel tuo metodo di installazione:

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

Quindi è possibile utilizzare l'istanza mockMvc per eseguire la richiesta.

Spero che questo aiuto.


Con questa soluzione dovrei configurare mockMvc in ogni classe di test. Questo può essere abbastanza noioso per molte classi di test!
Tempi

0

Secondo questa richiesta pull dagli sviluppatori della primavera, l'intestazione UTF-8 non è più richiesta e quindi è obsoleta. Se stai usando l'intestazione UTF-8 nella tua applicazione, potresti considerare di rimuoverla dall'applicazione invece di provare a correggere il test. Assicurati di utilizzare l' intestazione Content-Type: application / json e dovresti andare bene.


Penso che tu non capisca il problema. Ti suggerisco di leggere l'intera domanda e quindi di rivalutarla, se la tua risposta fornisce un valore. La mia applicazione funziona perfettamente, il problema è legato ai test.
Orari

Ho letto di nuovo l'intera domanda e ho rivalutato la mia risposta, la risposta è sempre la stessa. Nella tua domanda non spieghi perché l'intestazione è obsoleta, ho arricchito la tua domanda con il mio post. Ti suggerisco di leggere il PR che ho collegato, in modo da capire perché l'intestazione è obsoleta. Se capisci il perché, potresti prendere in considerazione la possibilità di modificare il test poiché il test sta testando il comportamento predefinito in Spring 2.1.X, ma non verifica correttamente il comportamento in Spring 2.2.X. Il comportamento di Spring è cambiato, il test dovrebbe cambiare di conseguenza se si accetta il nuovo comportamento di Spring.
scre_www

Non sei molto coerente qui. Nella tua risposta dici "[...] invece di provare a correggere il test". Nel tuo commento dici "[...] il tuo test dovrebbe cambiare di conseguenza se accetti il ​​nuovo comportamento di Spring".
Tempi

Ogni programmatore deve affrontare valori obsoleti di tanto in tanto. Quando qualcosa è deprecato, potresti risolverlo in qualche modo senza cercare perché è stato deprecato in primo luogo. Questo approccio sembra essere il modo in cui gestisci questo problema. Ora ti suggerisco di guardare oltre e cercare perché è diventato deprecato. Se lo capisci, puoi prendere una decisione migliore su cosa fare dopo. Nella tua domanda non c'è nulla sul perché ci dici solo che il tuo test sta fallendo a causa di un valore deprecato che è scarsa ricerca. Ho arricchito la domanda con alcune ricerche che non hai fatto E ho votato il Q.
scre_www

0

Sto usando Spring Boot 1.5.15.RELEASE e affrontato lo stesso problema durante la scrittura di test.

La prima soluzione che mi ha aiutato è stata l'aggiunta di .characterEncoding ("UTF-8")) in questo modo:

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

Sto usando un StandaloneMockMvcBuilder nella mia classe di test, quindi la seconda soluzione che mi ha aiutato è stata quella di creare un filtro, ad esempio:

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

e successivamente aggiungerlo al metodo standaloneSetup nella mia classe di test in questo modo:

@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

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

Questo problema non è Spring Boot, ma uno specifico di MockMvc, immagino. Pertanto, una soluzione alternativa deve essere applicata solo a MockMvc. ( JSON deve essere codificato utilizzando UTF-8 .)

problema correlato: gestione UTF-8 non corretta in MockMvc per risposta JSON · Numero # 23622 · progetti-primavera / quadro-primavera

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.