Spring 406 Not Acceptable HttpMediaTypeNotAcceptableException
2019年03月21日

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/45189189/spring-rest-request-406-not-acceptable-for-123?r=SearchResults

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