HttpMessageConverter
程序员文章站
2022-07-13 13:54:34
...
以StringHttpMessageConverter为例。
@RequestMapping("/rb") @ResponseBody public String locale() { User user = new User(); user.setId(1); return user.toString(); }
对于这个代码,结果和浏览器有关系。
Firefox的accpet是
Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
google chrome则是
Accept:application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5
而结果则也不相同。
firefox
google chrome
为什么会这样呢?
调试
<mvc:annotation-driven />开启了之后它给AnnotationMethodHandlerAdapter初始化7个转换器。
当发现一个方法上面有@ResponseBody注解,就调用Adapter的handleResponseBody方法。AnnotationMethodHandlerAdapter的方法:
private void handleResponseBody(Object returnValue, ServletWebRequest webRequest) throws Exception { if (returnValue == null) { return; } HttpInputMessage inputMessage = createHttpInputMessage(webRequest); HttpOutputMessage outputMessage = createHttpOutputMessage(webRequest); writeWithMessageConverters(returnValue, inputMessage, outputMessage); } 实际处理的是writeWithMessageConverters(returnValue, inputMessage, outputMessage);这句 private void writeWithMessageConverters(Object returnValue, HttpInputMessage inputMessage, HttpOutputMessage outputMessage) 方法: 首先是取出List<MediaType> acceptedMediaTypes = inputMessage.getHeaders().getAccept();请求中的accept信息。 这里取出来后,会遍历每个acceptedMediaTypes ,看有没有转换器能处理这个accpet。 随后有代码 for (HttpMessageConverter messageConverter : getMessageConverters()) { if (messageConverter.canWrite(returnValueType, acceptedMediaType)) { 这是遍历每个转换器,检查是否可以使用这个转换器处理。 StringHttpMessageConverter的canWrite被没有重写,而是使用AbstractHttpMessageConverter已经写好的canWrite方法。 public boolean canWrite(Class<?> clazz, MediaType mediaType) { return supports(clazz) && canWrite(mediaType); } 其中supports方法是 public boolean supports(Class<?> clazz) { return String.class.equals(clazz); } 而canWrite(mediaType);则是 protected boolean canWrite(MediaType mediaType) { if (mediaType == null || MediaType.ALL.equals(mediaType)) { return true; } for (MediaType supportedMediaType : getSupportedMediaTypes()) { if (supportedMediaType.isCompatibleWith(mediaType)) { return true; } } return false; } 它支持的格式有getSupportedMediaTypes()决定了。AbstractHttpMessageConverter默认的支持所有accpet。 直接请求过去的accpet内容当然是支持的。 回到writeWithMessageConverters方法,如果canWrite为true,下面则是 messageConverter.write(returnValue, acceptedMediaType, outputMessage); 进入,StringHttpMessageConverter还是没有重写过,使用AbstractHttpMessageConverter的方法。 HttpHeaders headers = outputMessage.getHeaders(); if (headers.getContentType() == null) { 判断回应头信息是否为空,空的话接下去,会判断acceptedMediaType(请求的accpet中的一个),如果可以处理,则将回应的accpet也设置为请求的accpet。否则为默认的(text/plain)。
因此可以看出问题出在这里。因为请求的accpet遍历是从第一个开始的。google chrome的accpet application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5第一个是 application/xml
回应的head accpet则也是 application/xml,return的信息不符合xml规范。
而firefox 的head accpet是
Content-Type text/html;charset=UTF-8
设置为text/html,所以答应出一个字符串当然没问题了。
推荐阅读
-
SPRING MVC3.2案例讲解--使用 Spring 3 MVC HttpMessageConverter 功能构建 RESTful web 服务
-
HttpMessageConverter
-
Spring HttpMessageConverter的作用及替换解析
-
no suitable HttpMessageConverter found for response type 异常处理
-
SpringMVC返回JSON数据格式及HttpMessageConverter介绍
-
no suitable HttpMessageConverter found for response type 异常处理
-
08点睛Spring MVC4.1-Spring MVC的配置(含自定义HttpMessageConverter)
-
SpringMVC返回JSON数据格式及HttpMessageConverter介绍