MockMvc ไม่สามารถจัดการอักขระ UTF-8 อีกต่อไปด้วย Spring Boot 2.2.0 ปล่อย


14

หลังจากฉันอัพเกรดเป็น2.2.0.RELEASESpring 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));
    }
...

นี่เป็นทางออกที่ง่ายที่สุดที่แนะนำที่นี่!
เวลา

คุณบันทึกวันของฉัน!
Filomat


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 header และคุณน่าจะใช้ได้


ฉันคิดว่าคุณไม่เข้าใจปัญหา ฉันขอแนะนำให้คุณอ่านคำถามทั้งหมดแล้วประเมินใหม่หากคำตอบของคุณให้คุณค่าใด ๆ แอปพลิเคชันของฉันถูกปลุกอย่างสมบูรณ์ดีปัญหาเกี่ยวข้องกับการทดสอบ
ครั้งที่

ฉันอ่านคำถามทั้งหมดอีกครั้งและประเมินคำตอบของฉันใหม่คำตอบก็ยังเหมือนเดิม ในคำถามของคุณคุณไม่ได้อธิบายว่าทำไมส่วนหัวจึงเลิกใช้แล้วฉันเติมคำถามของคุณด้วยโพสต์ของฉัน ฉันขอแนะนำให้คุณอ่าน PR ที่ฉันเชื่อมโยงด้วยเพื่อให้คุณเข้าใจว่าทำไมส่วนหัวจึงไม่สนับสนุน หากคุณเข้าใจว่าทำไมคุณอาจต้องเปลี่ยนการทดสอบเนื่องจากการทดสอบของคุณคือการทดสอบพฤติกรรมเริ่มต้นใน Spring 2.1.X แต่ไม่ได้ทดสอบพฤติกรรมใน Spring 2.2.X อย่างถูกต้อง การเปลี่ยนแปลงของ Spring มีผลต่อการทดสอบของคุณควรเปลี่ยนแปลงตามนั้นหากคุณยอมรับการกระทำของ Spring ใหม่
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);
    }
}

และเพิ่มในภายหลังไปยังวิธี standaloneSetup ในชั้นทดสอบของฉันเช่นนี้:

@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-projects / spring-framework

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.