升级到Spring 3.2后出现HttpMediaTypeNotAcceptableException

时间:2012-12-15 21:17:26

标签: java spring spring-mvc spring-3

将我的Spring MVC应用程序升级到Spring 3.2后,在访问我的一些URL时出现以下异常:

org.springframework.web.HttpMediaTypeNotAcceptableException: Could not find acceptable representation
    at org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping.handleNoMatch(RequestMappingInfoHandlerMapping.java:203) ~[spring-webmvc-3.2.0.RELEASE.jar:3.2.0.RELEASE]
    at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.lookupHandlerMethod(AbstractHandlerMethodMapping.java:272) ~[spring-webmvc-3.2.0.RELEASE.jar:3.2.0.RELEASE]
    at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.getHandlerInternal(AbstractHandlerMethodMapping.java:212) ~[spring-webmvc-3.2.0.RELEASE.jar:3.2.0.RELEASE]
    at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.getHandlerInternal(AbstractHandlerMethodMapping.java:55) ~[spring-webmvc-3.2.0.RELEASE.jar:3.2.0.RELEASE]
    at org.springframework.web.servlet.handler.AbstractHandlerMapping.getHandler(AbstractHandlerMapping.java:297) ~[spring-webmvc-3.2.0.RELEASE.jar:3.2.0.RELEASE]
    at org.springframework.web.servlet.DispatcherServlet.getHandler(DispatcherServlet.java:1091) ~[spring-webmvc-3.2.0.RELEASE.jar:3.2.0.RELEASE]
    at org.springframework.web.servlet.DispatcherServlet.getHandler(DispatcherServlet.java:1076) ~[spring-webmvc-3.2.0.RELEASE.jar:3.2.0.RELEASE]
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:896) ~[spring-webmvc-3.2.0.RELEASE.jar:3.2.0.RELEASE]
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:856) ~[spring-webmvc-3.2.0.RELEASE.jar:3.2.0.RELEASE]
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:915) [spring-webmvc-3.2.0.RELEASE.jar:3.2.0.RELEASE]
(...)

此异常导致HTTP 406无法接受。

我设法创建了一个带有我无法访问的URL的简化控制器:

@RequestMapping(value = "/resources/foo.js", produces = "text/javascript")
@ResponseBody
public String foo() throws Exception {
    return "";
}

由于我正在使用*/*标头中有Accept的普通浏览器,我不明白为什么我应该获得HTTP 406.这更让人感到奇怪的是这个代码正在使用Spring 3.1.2,但不适用于Spring 3.2。那是为什么?

4 个答案:

答案 0 :(得分:10)

Spring does content-negotiations in 3.2的方式有关的几处变化。其中一个变化是现在可以根据URL中的文件后缀完成内容协商。默认情况下启用此功能。在3.2之前的Spring版本中,HTTP accept-header用于内容协商。当浏览器访问您的URL时,内容协商很少成为问题,因为浏览器始终发送Accept:(...)*/*

Spring有一个后缀=>的地图媒体类型。对于“.js”,默认媒体类型是“application / x-javascript”。当Spring尝试查找请求到/resources/foo.js的处理程序映射时,它将与您的foo() - 方法不匹配,因为它会生成错误的媒体类型。

我不确定Spring团队是否考虑过这个案例。它至少有点奇怪,它允许您创建一个无法访问的@RequestMapping(因为.js-media类型与produce字段中设置的不兼容)。

有几种方法可以解决此问题。一种是将produce-parameter更改为“application / x-javascript”。另一种方法是将“.js”的媒体类型更改为“text / javascript”(see the docs of how to do that)。第三种可能性是基于后缀关闭内容协商(同样,see the docs of how to do it)。

答案 1 :(得分:2)

我现在已经通过根据请求路径的扩展禁用媒体类型来实现它。这可以通过以下方式完成:

    <mvc:annotation-driven content-negotiation-manager="contentNegotiationManager"/>
<bean id="contentNegotiationManager" class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
    <!-- Turn off working out content type based on URL file extension, should fall back to looking at the Accept headers -->
    <property name="favorPathExtension" value="false" />
</bean>

为所有xsd架构位置指定版本3.2。

答案 2 :(得分:0)

您需要在配置中添加适当的MessageConverter,以及杰克逊可能已经拥有的{。}}。

e.g。在您的WebMvcConfigurerAdapter的子类中:

@Override
public void configureMessageConverters(final List<HttpMessageConverter<?>> converters) {
    converters.add(new StringHttpMessageConverter());
}

当您仍然打开favorPathExtension选项时,您也不需要produces参数,您的控制器将返回application/javascript

当我遇到同样的问题时,Aleksanders的回答实际上并没有帮助我摆脱406。

答案 3 :(得分:0)

我有一个类似的问题,其中对控制器的休息调用是路径变量,其路径值中包含.au。 由于Spring Content Negotiation,Spring正在读取.au文件扩展名

REST GET调用是 http://localhost:8080/api/forgot-password/kk@kudeta.com.au 由于路径变量中的.au,Spring正在抛出org.springframework.web.HttpMediaTypeNotAcceptableException

我们已通过关闭基于内容的谈判解决了这个问题

@Configuration
public class ContentNegotiationConfig extends WebMvcConfigurerAdapter{
    @Override
    public void configureContentNegotiation(final 
     ContentNegotiationConfigurer configurer) {
        // Turn off suffix-based content negotiation
        configurer.favorPathExtension(false);
    }

}