SpringMVC异常报406 (Not Acceptable)的解决办法
异常信息如下
org.springframework.web.HttpMediaTypeNotAcceptableException: Could not find acceptable representation
因为在RequestMapping里面加上了
produces=MediaType.APPLICATION_JSON_VALUE
分析如下:
参见:https://www.cnblogs.com/wuxun1997/p/7729175.html
匹配逻辑:ProducesRequestCondition类185行
public ProducesRequestCondition getMatchingCondition(HttpServletRequest request) {
if (isEmpty()) {
return this;
}
Set<ProduceMediaTypeExpression> result = new LinkedHashSet<ProduceMediaTypeExpression>(expressions);
for (Iterator<ProduceMediaTypeExpression> iterator = result.iterator(); iterator.hasNext();) {
ProduceMediaTypeExpression expression = iterator.next();
if (!expression.match(request)) {
iterator.remove();
}
}
return (result.isEmpty()) ? null : new ProducesRequestCondition(result, this.contentNegotiationManager);
}解析请求Content-Type在这里,AbstractMappingContentNegotiationStrategy类
public List<MediaType> resolveMediaTypes(NativeWebRequest webRequest)
throws HttpMediaTypeNotAcceptableException {
return resolveMediaTypeKey(webRequest, getMediaTypeKey(webRequest));
}
/**
* An alternative to {@link #resolveMediaTypes(NativeWebRequest)} that accepts
* an already extracted key.
* @since 3.2.16
*/
public List<MediaType> resolveMediaTypeKey(NativeWebRequest webRequest, String key)
throws HttpMediaTypeNotAcceptableException {
if (StringUtils.hasText(key)) {
MediaType mediaType = lookupMediaType(key);
if (mediaType != null) {
handleMatch(key, mediaType);
return Collections.singletonList(mediaType);
}
mediaType = handleNoMatch(webRequest, key);
if (mediaType != null) {
addMapping(key, mediaType);
return Collections.singletonList(mediaType);
}
}
return Collections.emptyList();
}例如 URI 为 http://x.x.x.x/api/email/alice@gmail.com
则上面方法解析出来的 key 为"com", mediaType = "application/x-msdownload"
这显然是错的。
解决方法(来源于stackoverflow)
参见:
https://stackoverflow.com/questions/16332092/spring-mvc-pathvariable-with-dot-is-getting-truncated#
我试了很多都不行,总结一下,就是配置下面的两处
<bean id="contentNegotiationManager" class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean"> <property name="favorPathExtension" value="false" /> <property name="favorParameter" value="true" /> <property name="mediaTypes"> <value> json=application/json xml=application/xml </value> </property> </bean> <mvc:annotation-driven content-negotiation-manager="contentNegotiationManager"> <mvc:path-matching suffix-pattern="false" registered-suffixes-only="true" /> </mvc:annotation-driven>
一定要配置 contentNegotiationManager 和 registered-suffixes-only才行,当然也可以在Java代码里配置。
关于这个问题,我认真分析后,给Spring 社区提了一个issue,后续参见:
https://github.com/spring-projects/spring-framework/issues/22623