MockMvc không còn xử lý các ký tự UTF-8 với Spring Boot 2.2.0.RELEASE


14

Sau khi tôi nâng cấp lên 2.2.0.RELEASEphiên bản Spring Boot mới phát hành, một số thử nghiệm của tôi đã thất bại. Dường như MediaType.APPLICATION_JSON_UTF8đã bị phản đối và không còn được trả về là loại nội dung mặc định từ các phương thức điều khiển không chỉ định rõ ràng loại nội dung.

Kiểm tra mã như

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

đột nhiên không hoạt động nữa vì loại nội dung không khớp như hình bên dưới

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

Thay đổi mã để .andExpect(content().contentType(MediaType.APPLICATION_JSON))giải quyết vấn đề ngay bây giờ.

Nhưng bây giờ khi so sánh contentvới đối tượng được tuần tự hóa dự kiến ​​vẫn còn một sự không phù hợp nếu có bất kỳ ký tự đặc biệt nào trong đối tượng. Dường như .getContentAsString()phương thức này không sử dụng mã hóa ký tự UTF-8 theo mặc định (bất kỳ nữa).

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

Làm cách nào tôi có thể nhận được contentmã hóa UTF-8?

Câu trả lời:


7

Đúng. Đây là vấn đề từ mùa xuân 2.2.0 khởi động. Họ đặt khấu hao cho mã hóa bảng mã mặc định.

.getContentAsString(StandardCharsets.UTF_8) - tốt nhưng trong mọi phản hồi sẽ được điền theo mặc định ISO 8859-1.

Trong dự án của tôi, tôi đã cập nhật trình chuyển đổi được tạo hiện tại:

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

Đây là giải pháp dễ nhất được đề nghị ở đây!
Thời gian

bạn đã cứu ngày của tôi!
Filomat


2

Ký tự mã hóa mặc định không còn là UTF-8 kể từ phiên bản 5.2.0 của lò xo.

Để tiếp tục sử dụng UTF-8, bạn phải đặt nó trong ServletResponse của kết quả MockMvc. Để đặt mã hóa ký tự mặc định thành UTF-8, hãy thực hiện thao tác như thế này trong phương thức thiết lập của bạn:

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

Sau đó, bạn có thể sử dụng ví dụ mockMvc để thực hiện yêu cầu của mình.

Hy vọng điều này giúp đỡ.


Với giải pháp này, tôi sẽ phải cấu hình mockMvc trong mọi lớp kiểm tra. Điều này có thể khá tẻ nhạt đối với nhiều lớp kiểm tra!
Thời gian

0

Theo yêu cầu kéo này từ các nhà phát triển mùa xuân, tiêu đề UTF-8 không còn cần thiết nữa và do đó nó không được dùng nữa. Nếu bạn đang sử dụng tiêu đề UTF-8 trong ứng dụng của mình, bạn có thể cân nhắc xóa nó khỏi ứng dụng của mình thay vì cố gắng sửa bài kiểm tra của mình. Chỉ cần đảm bảo rằng bạn đang sử dụng tiêu đề Content-Type: application / json và bạn sẽ ổn.


Tôi nghĩ bạn không hiểu vấn đề. Tôi đề nghị bạn đọc toàn bộ câu hỏi và sau đó đánh giá lại, nếu câu trả lời của bạn mang lại bất kỳ giá trị nào. Ứng dụng của tôi là wokring hoàn toàn tốt, vấn đề liên quan đến các bài kiểm tra.
Thời gian

Tôi đọc lại toàn bộ câu hỏi và đánh giá lại câu trả lời của mình, câu trả lời vẫn vậy. Trong câu hỏi của bạn, bạn không giải thích lý do tại sao tiêu đề bị phản đối, tôi đã làm phong phú câu hỏi của bạn bằng bài đăng của tôi. Tôi đề nghị bạn đọc PR mà tôi đã liên kết, để bạn hiểu lý do tại sao tiêu đề bị phản đối. Nếu bạn hiểu lý do tại sao, bạn có thể muốn xem xét thay đổi thử nghiệm của mình vì thử nghiệm của bạn đang thử nghiệm hành vi mặc định trong Spring 2.1.X, nhưng nó không kiểm tra chính xác hành vi trong Spring 2.2.X. Hành vi Spring đã thay đổi, thử nghiệm của bạn sẽ thay đổi tương ứng nếu bạn chấp nhận hành vi Spring mới.
scre_www

Bạn không nhất quán ở đây. Trong câu trả lời của bạn, bạn nói "[...] thay vì cố gắng sửa bài kiểm tra của mình". Trong bình luận của bạn, bạn nói "[...] bài kiểm tra của bạn sẽ thay đổi tương ứng nếu bạn chấp nhận hành vi Mùa xuân mới."
Thời gian

Mọi lập trình viên đều phải đối mặt với các giá trị không được chấp nhận ngay bây giờ. Khi một cái gì đó bị phản đối, bạn có thể sửa nó bằng cách nào đó mà không cần nghiên cứu tại sao nó bị phản đối ngay từ đầu. Cách tiếp cận này dường như là cách bạn xử lý vấn đề này. Bây giờ tôi đề nghị bạn nhìn xa hơn và nghiên cứu lý do tại sao nó bị phản đối. Nếu bạn hiểu điều đó, bạn có thể đưa ra quyết định tốt hơn về những việc cần làm tiếp theo. Trong câu hỏi của bạn không có gì về lý do tại sao bạn chỉ cho chúng tôi biết bài kiểm tra của bạn không thành công do giá trị không được chấp nhận, đó là nghiên cứu kém. Tôi đã làm phong phú thêm câu hỏi với một số nghiên cứu mà bạn chưa thực hiện VÀ nâng cấp Q.
scre_www

0

Tôi đang sử dụng Spring Boot 1.5.15.RELEASE và gặp vấn đề tương tự khi viết bài kiểm tra.

Giải pháp đầu tiên giúp tôi là thêm .characterEncoding ("UTF-8")) như thế này:

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

Tôi đang sử dụng StandaloneMockMvcBuilder trong lớp thử nghiệm của mình, vì vậy giải pháp thứ hai giúp tôi là tạo bộ lọc, ví dụ:

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

và sau đó thêm nó vào phương thức độc lập trong lớp thử nghiệm của tôi như thế này:

@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

Cài đặt bổ sung cho 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();

Vấn đề này không phải là Spring Boot, mà là một vấn đề cụ thể của MockMvc, tôi đoán vậy. Vì vậy, một cách giải quyết phải được áp dụng cho MockMvc. ( JSON phải được mã hóa bằng UTF-8 .)

vấn đề liên quan: Xử lý UTF-8 không đúng cách trong MockMvc cho phản hồi JSON · Vấn đề # 23622 · dự án mùa xuân / khung công tác mùa xuân

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.