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

Joh*_*rde 3 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");
}       
Run Code Online (Sandbox Code Playgroud)

它使用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);
    });
});
Run Code Online (Sandbox Code Playgroud)

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

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

无论如何都要覆盖此行为而不必编码.(点)在文件名中?

And*_*son 10

默认情况下,Spring MVC在尝试确定响应请求的媒体类型时,更喜欢使用请求的路径.这在javadoc中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);
    }
}
Run Code Online (Sandbox Code Playgroud)