`
liyixing1
  • 浏览: 958177 次
  • 性别: Icon_minigender_1
  • 来自: 江西上饶
社区版块
存档分类
最新评论

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


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,所以答应出一个字符串当然没问题了。
  • 大小: 33.7 KB
  • 大小: 12.4 KB
  • 大小: 29 KB
分享到:
评论
2 楼 liyixing1 2012-11-09  
sjbrising 写道
spring mvs的源码都看过吧。分析的很细致啊。

嗯看过一部分而已
1 楼 sjbrising 2012-10-25  
spring mvs的源码都看过吧。分析的很细致啊。

相关推荐

Global site tag (gtag.js) - Google Analytics