MockMvc tidak lagi menangani karakter UTF-8 dengan Spring Boot 2.2.0.RELEASE

14

Setelah saya memutakhirkan ke versi yang baru dirilis 2.2.0.RELEASESpring Boot beberapa tes saya gagal. Tampaknya MediaType.APPLICATION_JSON_UTF8sudah usang dan tidak lagi dikembalikan sebagai tipe konten default dari metode pengontrol yang tidak menentukan tipe konten secara eksplisit.

Kode uji suka

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

tiba-tiba tidak berfungsi lagi karena jenis konten tidak cocok seperti yang ditunjukkan di bawah ini

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

Mengubah kode untuk .andExpect(content().contentType(MediaType.APPLICATION_JSON))menyelesaikan masalah untuk saat ini.

Tetapi sekarang ketika membandingkan contentdengan objek serial yang diharapkan masih ada ketidakcocokan jika ada karakter khusus dalam objek. Tampaknya .getContentAsString()metode ini tidak menggunakan pengkodean karakter UTF-8 secara default (lagi).

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

Bagaimana saya bisa masuk contentdalam pengkodean UTF-8?

Waktu
sumber

Jawaban:

7

Iya. Ini masalah dari 2.2.0 spring-boot. Mereka menetapkan penghentian untuk pengkodean charset default.

.getContentAsString(StandardCharsets.UTF_8) - baik tetapi dalam respons apa pun akan diisi ISO 8859-1 secara default.

Dalam proyek saya, saya memperbarui konverter yang dibuat saat ini:

@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));
    }
...
Alexander Someoneperson
sumber
Ini adalah solusi termudah yang direkomendasikan di sini!
Times
kamu menyelamatkan hariku!
Filomat
2

Karakter penyandian default tidak lagi UTF-8 sejak versi 5.2.0 dari pegas.

Untuk terus menggunakan UTF-8, Anda harus mengaturnya di ServletResponse dari hasil MockMvc. Untuk mengatur pengkodean karakter default ke UTF-8, lakukan sesuatu seperti ini dalam metode pengaturan Anda:

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

Kemudian Anda dapat menggunakan contoh mockMvc untuk melakukan permintaan Anda.

Semoga bantuan ini.

black4bird
sumber
Dengan solusi ini saya harus mengkonfigurasi mockMvc di setiap kelas uji. Ini bisa sangat membosankan bagi banyak kelas ujian!
Times
0

Menurut permintaan tarik ini dari pengembang musim semi header UTF-8 tidak diperlukan lagi dan karena itu sudah usang. Jika Anda menggunakan header UTF-8 di aplikasi Anda, Anda mungkin mempertimbangkan untuk menghapusnya dari aplikasi Anda alih-alih mencoba memperbaiki tes Anda. Pastikan Anda menggunakan header Content-Type: application / json dan Anda akan baik-baik saja.

scre_www
sumber
Saya pikir Anda tidak mengerti masalahnya. Saya sarankan Anda membaca seluruh pertanyaan dan kemudian mengevaluasi kembali, jika jawaban Anda memberikan nilai. Aplikasi saya baik-baik saja wokring, masalahnya terkait dengan tes.
Times
Saya membaca seluruh pertanyaan lagi dan mengevaluasi kembali jawaban saya, jawabannya masih sama. Dalam pertanyaan Anda, Anda tidak menjelaskan mengapa tajuk tidak digunakan lagi, saya memperkaya pertanyaan Anda dengan kiriman saya. Saya sarankan Anda membaca PR yang saya tautkan, sehingga Anda mengerti mengapa header tidak digunakan lagi. Jika Anda memahami alasannya, Anda mungkin ingin mempertimbangkan untuk mengubah tes Anda karena tes Anda menguji perilaku default di Spring 2.1.X, tetapi itu tidak menguji perilaku di Spring 2.2.X dengan benar. Perilaku Spring berubah, tes Anda harus berubah sesuai jika Anda menerima perilaku Spring baru.
scre_www
Anda tidak terlalu konsisten di sini. Dalam jawaban Anda, Anda mengatakan "[...] alih-alih mencoba memperbaiki tes Anda". Dalam komentar Anda, Anda mengatakan "[...] tes Anda akan berubah sesuai jika Anda menerima perilaku Musim Semi yang baru."
Times
Setiap programmer menghadapi nilai-nilai usang sekarang dan kemudian. Ketika sesuatu sudah usang, Anda bisa memperbaikinya entah bagaimana tanpa meneliti mengapa itu sudah usang. Pendekatan ini tampaknya menjadi cara Anda menangani masalah ini. Sekarang saya sarankan Anda melihat lebih jauh dan mencari tahu mengapa itu sudah usang. Jika Anda mengerti itu, Anda dapat membuat keputusan yang lebih baik tentang apa yang harus dilakukan selanjutnya. Dalam pertanyaan Anda, tidak ada alasan mengapa Anda hanya memberi tahu kami bahwa tes Anda gagal karena nilai usang yang merupakan penelitian yang buruk. Saya memperkaya pertanyaan dengan beberapa penelitian yang tidak Anda lakukan DAN mengangkat Q.
scre_www
0

Saya menggunakan Spring Boot 1.5.15.RELEASE dan menghadapi masalah yang sama saat menulis tes.

Solusi pertama yang membantu saya adalah menambahkan .characterEncoding ("UTF-8")) seperti ini:

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

Saya menggunakan StandaloneMockMvcBuilder di kelas pengujian saya, jadi solusi kedua yang membantu saya adalah membuat filter misalnya:

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

dan kemudian menambahkannya ke metode standaloneSetup di kelas pengujian saya seperti ini:

@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();
}
Zuljen
sumber
0

Pengaturan tambahan untuk 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();

Masalah ini bukan Spring Boot, tapi MockMvc yang spesifik, kurasa. Jadi, solusi harus diterapkan ke MockMvc saja. ( JSON harus dikodekan menggunakan UTF-8 .)

masalah terkait: Penanganan UTF-8 yang tidak benar di MockMvc untuk respons JSON · Edisi # 23622 · pegas-proyek / pegas-kerangka kerja

yukihane
sumber