HttpMessageConverter

以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
[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,所以答应出一个字符串当然没问题了。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值