HttpMediaTypeNotAcceptableException after upgrading to Spring 3.2

跟風遠走 提交于 2019-12-21 00:13:31

问题


After upgrading my Spring MVC application to Spring 3.2 I'm getting the following exception when accessing some of my URLs:

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]
(...)

This exception results to a HTTP 406 NOT ACCEPTABLE.

I've managed to create a simplified controller with a URL I cannot access:

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

As I'm using a normal browser which has */* in the Accept-header, I don't see why I should get a HTTP 406. What makes this even more strange is that this code is working with Spring 3.1.2, but not with Spring 3.2. Why is that?


回答1:


There have been several changes related to how Spring does content-negotiations in 3.2. One of these changes is that content negotiations can now be done based on the file suffix in the URL. This feature is enabled by default. In Spring versions prior to 3.2 the HTTP accept-header were used for content-negotiations. When browsers accessed your URLs content-negotiation was seldom an issue, as browser always sends Accept:(...)*/*.

Spring has a map of suffix => Media type. For ".js" the default media type is "application/x-javascript". When Spring tries to lookup the handler mapping for a request to /resources/foo.js, it won't match your foo()-method as it produces the wrong media type.

I'm not sure if the Spring team has thought through this case. It is at least a bit strange that it lets you create a @RequestMapping which cannot be accessed (because of the incompatibility between the .js-media type and what is set in the produces field).

There are several ways of fixing this issue. One is to change the produces-parameter to "application/x-javascript". Another would be to change the media type of ".js" to "text/javascript" (see the docs of how to do that). A third possibility is to turn off content-negotiations based on suffixes (again, see the docs of how to do it).




回答2:


I've now got it working by disabling the getting of media type based on the extension of the requested path. This can be done by the following:

    <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>

And specify version 3.2 for all the xsd schema locations.




回答3:


You need to add a proper MessageConverter to your configuration, along with one you might already have for Jackson.

e.g. in your subclass of WebMvcConfigurerAdapter:

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

When you still keep the favorPathExtension option turned on, you won't require a produces parameter as well, your controller will return application/javascript.

The hints in Aleksanders answer actually did not help me getting rid of the 406 when I had the same problem.




回答4:


I have a similar issue where rest call to the controller is having path variable which contains .au in path value. Spring is reading .au as file extention due to spring Content Negotiation

REST GET call is http://localhost:8080/api/forgot-password/kk@kudeta.com.au due to .au in path variable Spring is throwing org.springframework.web.HttpMediaTypeNotAcceptableException

We have resolved it by turning off content based negotiation

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

}


来源:https://stackoverflow.com/questions/13896286/httpmediatypenotacceptableexception-after-upgrading-to-spring-3-2

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!