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