以StringHttpMessageConverter为例。
对于这个代码,结果和浏览器有关系。
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
[img]http://dl.iteye.com/upload/attachment/501859/bb81887d-2eba-354c-b181-a3fc969799cd.jpg[/img]
google chrome
[img]http://dl.iteye.com/upload/attachment/501861/37936a11-bdea-3f1e-9826-150c8ae8b4f1.jpg[/img]
为什么会这样呢?
调试
<mvc:annotation-driven />开启了之后它给AnnotationMethodHandlerAdapter初始化7个转换器。
[img]http://dl.iteye.com/upload/attachment/501853/9226cf9c-0561-3abb-97c6-c3d13b36a31d.jpg[/img]
当发现一个方法上面有@ResponseBody注解,就调用Adapter的handleResponseBody方法。AnnotationMethodHandlerAdapter的方法:
因此可以看出问题出在这里。因为请求的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,所以答应出一个字符串当然没问题了。
@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
[img]http://dl.iteye.com/upload/attachment/501859/bb81887d-2eba-354c-b181-a3fc969799cd.jpg[/img]
google chrome
[img]http://dl.iteye.com/upload/attachment/501861/37936a11-bdea-3f1e-9826-150c8ae8b4f1.jpg[/img]
为什么会这样呢?
调试
<mvc:annotation-driven />开启了之后它给AnnotationMethodHandlerAdapter初始化7个转换器。
[img]http://dl.iteye.com/upload/attachment/501853/9226cf9c-0561-3abb-97c6-c3d13b36a31d.jpg[/img]
当发现一个方法上面有@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,所以答应出一个字符串当然没问题了。