【问题标题】:Assume content-type of JSON in Spring MVC controller在 Spring MVC 控制器中假设 JSON 的内容类型
【发布时间】:2013-10-10 15:32:13
【问题描述】:

我有一个类似这个的 Spring 3.1 Controller 方法

@RequestMapping(method = RequestMethod.POST)
public void (@RequestBody SomeObject obj) {
    // Do something
}

spring 配置文件已正确设置以接受 JSON。如果我发送内容类型设置为“application/json”的请求并以 JSON 格式发送正确的正文,一切都会按预期进行。

如果我没有将 Content Type 指定为“application/json”,则返回 HTTP 415,这也是基于配置的预期。不管内容类型如何,是否告诉 Spring 始终将 RequestBody 视为 JSON?

【问题讨论】:

  • 别这么想。来自文档:MappingJackson2HttpMessageConverter(或使用 Jackson 1.x 的 MappingJacksonHttpMessageConverter)一个 HttpMessageConverter 实现,可以使用 Jackson 的 ObjectMapper 读取和写入 JSON。 JSON 映射可以通过使用 Jackson 提供的注释根据需要进行自定义。当需要进一步控制时,可以通过 ObjectMapper 属性注入自定义 ObjectMapper,以应对需要为特定类型提供自定义 JSON 序列化器/反序列化器的情况。默认情况下,此转换器支持 (application/json)。

标签: spring-mvc


【解决方案1】:

为了处理@RequestBody注解的参数并注入一个参数,Spring使用RequestResponseBodyMethodProcessor。这个HandlerMethodArgumentResolver 做的第一件事是检查Content-Type 标头。如果缺少它,则默认为application/octet-stream。然后它获取已注册的HttpMessageConverter 实例列表。默认情况下,这些是

StringHttpMessageConverter stringConverter = new StringHttpMessageConverter();
stringConverter.setWriteAcceptCharset(false);

messageConverters.add(new ByteArrayHttpMessageConverter()); // if your argument is a byte[]
messageConverters.add(stringConverter); // if your argument is a String
messageConverters.add(new ResourceHttpMessageConverter()); // if your argument is a Resource
messageConverters.add(new SourceHttpMessageConverter<Source>()); // if your argument is one of the javax.xml Source classes
messageConverters.add(new AllEncompassingFormHttpMessageConverter());  // for application/x-www-form-urlencoded content-type
if (romePresent) {
    messageConverters.add(new AtomFeedHttpMessageConverter()); // for application/atom+xml content-type
    messageConverters.add(new RssChannelHttpMessageConverter()); // for application/rss+xml content-type
}
if (jaxb2Present) {
    messageConverters.add(new Jaxb2RootElementHttpMessageConverter()); // if your argument class is annotated with @XmlRootElement or @XmlType
}
if (jackson2Present) {
    messageConverters.add(new MappingJackson2HttpMessageConverter()); // for content-type application/json and application/*+json (wildcard json)
}
else if (jacksonPresent) {
    messageConverters.add(new MappingJacksonHttpMessageConverter()); // in case, but rarely, same as above
}

RequestResponseBodyMethodProcessor 然后按顺序遍历此列表,并在每个 HttpMessageConverter 上调用 canRead()。如果它返回true,则RequestResponseBodyMethodProcessor 使用该HttpMessageConverter 来创建参数。如果它永远找不到,它会抛出一个HttpMediaTypeNotSupportedException,这使得DispatcherServlet 发送一个415 响应。

使用上述默认值,这是不可能的。您必须创建并注册自己的 HttpMessageConverter 才能做到这一点。请注意,它将适用于所有带有 @RequestBody 注释参数的处理程序方法。


作为建议,Content-Type 标头专门用于此场景,您应该使用它。

【讨论】:

  • 我能够建议我们向客户要求他们正确设置 Content-Type 标头。
猜你喜欢
  • 2014-04-06
  • 2011-05-23
  • 1970-01-01
  • 2015-08-13
  • 1970-01-01
  • 1970-01-01
  • 2014-10-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多