最近使用spring4.0.5版本的Mvc,json请求时,客户端报错,406 Not Acceptable。
原因分析
在百度GOOGLE半天无果后,果断开始debug。
首先定位在org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor类中的下面代码处抛出了异常。
if (compatibleMediaTypes.isEmpty()) {
throw new HttpMediaTypeNotAcceptableException(producibleMediaTypes);
}
由此看来是compatibleMediaTypes为空导致的,由于之前一直使用spring3.1没有出现够相关的问题,于是切换到3.1继续debug,发现3.1的requestedMediaTypes为[*/*], 而3.2的requestedMediaTypes却为[text/html]。到此几乎可以确定在3.1版本与4.0.5版本中获取acceptableMediaTypes的方式肯定是有所差异的。
定位到每个版本的getAcceptableMediaTypes方法上,继续查看。
spring 3.1
private List<MediaType> getAcceptableMediaTypes(
HttpInputMessage inputMessage) {
try {
List<MediaType> result = inputMessage.getHeaders().getAccept();
return result.isEmpty() ? Collections.singletonList(MediaType.ALL)
: result;
} catch (IllegalArgumentException ex) {
if (logger.isDebugEnabled()) {
logger.debug("Could not parse Accept header: "
+ ex.getMessage());
}
return Collections.emptyList();
}
}
spring 4.0.5
进入到getAcceptableMediaTypes方法,发现通过resolveMediaTypes获取MediaType的。
private List<MediaType> getAcceptableMediaTypes(HttpServletRequest request) throws HttpMediaTypeNotAcceptableException {
List<MediaType> mediaTypes = this.contentNegotiationManager.resolveMediaTypes(new ServletWebRequest(request));
return (mediaTypes.isEmpty() ? Collections.singletonList(MediaType.ALL) : mediaTypes);
}
接着进入resolveMediaTypes方法
@Override
public List<MediaType> resolveMediaTypes(NativeWebRequest webRequest) throws HttpMediaTypeNotAcceptableException {
for (ContentNegotiationStrategy strategy : this.contentNegotiationStrategies) {
List<MediaType> mediaTypes = strategy.resolveMediaTypes(webRequest);
if (mediaTypes.isEmpty() || mediaTypes.equals(MEDIA_TYPE_ALL)) {
continue;
}
return mediaTypes;
}
return Collections.emptyList();
}
看来问题就是出在这里了。
解决办法
办法一
1、导入第三方的jackson包,jackson-mapper-asl-1.9.7.jar和jackson-core-asl-1.9.7.jar。
2、Spring配置文件添加:
<mvc:annotation-driven/>
<!-- 避免IE执行AJAX时,返回JSON出现下载文件 -->
<bean id="mappingJacksonHttpMessageConverter" class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>text/html;charset=UTF-8</value>
</list>
</property>
</bean>
<!-- 启动Spring MVC的注解功能,完成请求和注解POJO的映射 -->
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<list>
<ref bean="mappingJacksonHttpMessageConverter" /><!-- json转换器 -->
</list>
</property>
</bean>
办法二
1、导入第三方的fastjson包,fastjson-1.1.34.jar
2、Spring配置文件添加:
<mvc:annotation-driven>
<mvc:message-converters register-defaults="true">
<!-- 避免IE执行AJAX时,返回JSON出现下载文件 -->
<bean id="fastJsonHttpMessageConverter" class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>application/json;charset=UTF-8</value>
</list>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>