spring requestmapping文件扩展名为http错误406

时间:2015-01-24 01:51:46

标签: java ajax json http-headers spring-boot

我已创建此REST映射,以便它可以接受URI末尾的文件名...

@RequestMapping(value="/effectrequest/{name}/{imagename:[a-zA-Z0-9%\\.]*}", 
        headers="Accept=*/*", method=RequestMethod.GET, 
        produces = "application/json")
public @ResponseBody EffectRequest effectRequest(
        @PathVariable("name") String name,
        @PathVariable("imagename") String imageName)
{
    return new EffectRequest(2, "result");
}       

使用MappingJackson2HttpMessageConverter返回JSON内容。我使用...

对这个映射进行了测试jQuery AJAX调用
var effectName = 'Blur';
var imageName = 'Blah.jpg';
var requestUri = '/effectrequest/' + effectName + '/' + imageName;
alert(requestUri);

$(document).ready(function() {
$.ajax({
        url: /*[+   [[${hostname}]] + requestUri   +]*/
    }).then(function(data) {
       $('.effect').append(data.id);
       $('.image').append(data.content);
    });
});

这会生成一个http://localhost/effectrequest/Blur/Blah.jpg的URI,并且在调试会话中,在上面的effectRequest()方法中正确接收文件名。但是,即使在RequestMapping中使用produces = "application/json",客户端或jQuery AJAX调用也会从服务器收到HTTP 406错误(不可接受)。

经过多次调试后,我缩小了范围 - 当我修改测试javascript代码以生成http://localhost/effectrequest/Blur/Blah.json的URI时,它可以工作。因此,Tomcat或MappingJackson2HttpMessageConverter通过查看URI末尾的文件扩展名并确定我发回的JSON内容不是很好的匹配来导致HTTP 406错误。

无论如何都要重写此行为而不必编码。文件名中的(点)?

1 个答案:

答案 0 :(得分:10)

默认情况下,Spring MVC在尝试找出对请求的响应的媒体类型时,更喜欢使用请求的路径。这在javadoc for ContentNegotiationConfigurer.favorPathExtension()

中有所描述
  

指示是否应使用请求路径的扩展名来确定具有最高优先级的请求媒体类型。

     

默认情况下,此值设置为true,在这种情况下,/hotels.pdf的请求将被解释为"application/pdf"的请求,无论Accept标头如何。

在您的情况下,这意味着/effectrequest/Blur/Blah.jpg的请求被解释为对image/jpeg的请求,MappingJackson2HttpMessageConveter尝试撰写image/jpeg无法回复的请求要做。

您可以使用ContentNegotiationConfigurer扩展WebMvcConfigurerAdapter来轻松更改此配置。例如:

@SpringBootApplication
public class Application extends WebMvcConfigurerAdapter {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

    @Override
    public void configureContentNegotiation(
            ContentNegotiationConfigurer configurer) {
        configurer.favorPathExtension(false);
    }
}