spring 休息模板中的无效 MIME 类型?

Invalid mime type in spring rest template?

我只是想发出一个简单的 REST 请求,如下所示

String url = "some url";
MultiValueMap<String, String> headers = new LinkedMultiValueMap<>();
headers.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
headers.add(HttpHeaders.AUTHORIZATION, "some authorization");
RestTemplate restTemplate = new RestTemplate();
restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
Body body = new Body();
body.setRemarks("test");
org.springframework.http.HttpEntity request = new org.springframework.http.HttpEntity(body, headers);
try {
    ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.PUT, request, String.class);
    System.out.println("Status Response: "+ response.getStatusCode() +". Body: "+ response.getBody());
} catch (HttpClientErrorException | HttpServerErrorException e) {
    e.printStackTrace();
} catch (Exception e) {
    e.printStackTrace();
}

问题是每次我在 Java 中执行此操作时,结果都是不可预测的,我通常会不断收到此错误。

org.springframework.http.InvalidMediaTypeException: Invalid mime type "text/plain, application/json, application/json, application/*+json, application/*+json, */*; charset=UTF-8": Invalid token character ',' in token "plain, application/json, application/json, application/*+json, application/*+json, */*"
at org.springframework.http.MediaType.parseMediaType(MediaType.java:452)
at org.springframework.http.HttpHeaders.getContentType(HttpHeaders.java:745)
at org.springframework.web.client.DefaultResponseErrorHandler.getCharset(DefaultResponseErrorHandler.java:115)
at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:63)
at org.springframework.web.client.RestTemplate.handleResponse(RestTemplate.java:700)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:653)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:613)
at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:531)

但是,当我通过邮递员尝试相同的请求时,它起作用了。我遗漏了一些非常简单的东西,我不知道是什么。

我检查了 Postman 和 headers 的回复,它们看起来像 Content-Type →application/json; charset=UTF-8 一样好,而且回复也格式正确。

我也无法确定请求或响应是在哪个 Rest 模板上出现问题的部分。

我的简短回答是在发出请求之前添加这些额外的 headers。

headers.add(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE);
headers.add(HttpHeaders.ACCEPT_CHARSET, StandardCharsets.UTF_8.name());

长答案:感谢 Nikolay Shevchenko's 建议使用调试器来挖掘当服务器出现错误时 RestTemplate 试图收集所有 headers 和 body 从响应中创建理智的异常消息。在尝试从响应中创建该消息时,它获得了 MIME 类型

text/plain, application/json, application/json, application/*+json, application/*+json, */*; charset=UTF-8

是的,整个文本长度而不是 application/json; charset=UTF-8,如上面提供的 mime 类型 Postman. So in my case of an older spring rest template version when it tries to parse over 的相同请求所示,它失败了,产生了这条消息。

org.springframework.http.InvalidMediaTypeException: Invalid mime type "text/plain, application/json, application/json, application/*+json, application/*+json, */*; charset=UTF-8": Invalid token character ',' in token "plain, application/json, application/json, application/*+json, application/*+json, */*"

因此,不是出现服务器错误,而是从更深的堆栈中冒出一个更细粒度的 mime 类型异常,这对您正在搜索的内容毫无意义。

根据 this post by M. Deinum RestTemplate 是如何最终使用 StringHttpMessageConverter 的,尽管我已经指定了 Jackson 到 Http 消息转换器,如下所示。

restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());

正如前面提到的 post 中提到的 StringHttpMessageConverter 导致 writeAcceptCharset 成为 true 这带来了 MIME 类型的长格式,几乎所有可能的值。在提到的 post 中,解决方案要么将 writeAcceptCharset 设为 false,要么不编写纯字符串,而是使用 object,然后将其编组为字符串。

对于我的用例,我期望响应类型为 application/json,字符集为 UTF-8,因此在配置中设置那些接受 headers 解决了我的问题。