欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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
HttpMessageConverter
            
    
    博客分类: p.spring ChromeITeyeFirefoxXMLGoogle 

google chrome

HttpMessageConverter
            
    
    博客分类: p.spring ChromeITeyeFirefoxXMLGoogle 

为什么会这样呢?

调试

<mvc:annotation-driven />开启了之后它给AnnotationMethodHandlerAdapter初始化7个转换器。


HttpMessageConverter
            
    
    博客分类: p.spring ChromeITeyeFirefoxXMLGoogle 

当发现一个方法上面有@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,所以答应出一个字符串当然没问题了。
  • HttpMessageConverter
            
    
    博客分类: p.spring ChromeITeyeFirefoxXMLGoogle 
  • 大小: 33.7 KB
  • HttpMessageConverter
            
    
    博客分类: p.spring ChromeITeyeFirefoxXMLGoogle 
  • 大小: 12.4 KB
  • HttpMessageConverter
            
    
    博客分类: p.spring ChromeITeyeFirefoxXMLGoogle 
  • 大小: 29 KB