3

我正在尝试使用 Spring MVC 3.2 编写一个使用/生成 JSON 和 HTML 的控制器。我有两个产生不同内容类型的处理程序方法:

@Controller
public class FooController {
    @RequestMapping(value="/foo", produces="text/html")
    public String fooHTML() {
        // ...
    }

    @RequestMapping(value="/foo", produces="application/json")
    public String fooJSON() {
        // ...
    }
}

如果Accept来自客户端的标头包含text/htmlor application/json,这将非常有效

...但后来出现了 Internet Explorer。如此处所述,IE 的Accept标头各不相同,但它从不包含text/html并且始终*/*位于末尾。当 Spring 收到来自 IE 的请求时,它看不到与我的控制器生成的内容类型直接相等的内容类型,但是,锁定*/*通配符,它​​(正确地)决定两种映射都适用。

面对多个匹配的处理程序映射,Spring(在 RequestMappingHandlerMapping bean 中)按照字典顺序对映射进行排序,选择第一个,然后继续。从我的角度来看,问题在于这个过程优先application/jsontext/html. 除非客户端特别请求,否则我宁愿返回text/htmlapplication/json——这样,我可以将 HTML 提供给 IE 等愚蠢的客户端,将 JSON 提供给我的 API 用户等精通内容类型的客户端。

有谁知道不需要扩展 RequestMappingHandlerMapping 来对处理程序进行不同排序的方法?你有什么简单的解决方法吗?

注意:我尝试在 ContentNegotiationManager 中设置默认内容类型,如Spring blog中所述。它不能解决我的问题,因为该设置仅在未指定 Accept 标头时生效。

4

2 回答 2

1

一种解决方案是通过其参数降低fooJSON()优先级。value

在实践中,模式/foo/foo{1}是等价的。但是,第二个被认为是“更通用的”并且最后使用:

@Controller
public class FooController {
    @RequestMapping(value="/foo", produces="text/html")
    public String fooHTML() {
        // ...
    }

    @RequestMapping(value="/foo{1}", produces="application/json")
    //                         ^^^------- changed here
    public String fooJSON() {
        // ...
    }
}

这边走:

  • text/htmlfooHTML()
  • application/jsonfooJSON()
  • */*fooHTML()
  • 其他任何事情都会产生406 - Not Acceptable错误
于 2013-06-06T20:06:45.757 回答
1

我发现解决此问题的一种方法是将 ALL mimetype 添加到您的请求映射中,该映射提供响应的 HTML 版本。

@RequestMapping(value="/foo", produces={"text/html", "*/*"})
public String fooHTML() {
    // ...
}

这确实意味着 HTML 响应是为任何以前未映射的 mime 类型提供的。就我而言,这种行为是需要的,但如果您需要返回 406(不可接受)响应代码,那么这对您不起作用。

于 2015-05-21T12:03:38.660 回答