我正在尝试使用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/html
或application/json
,
...但是那时有Internet Explorer。如上所述here,IE的Accept
标头各不相同,但它从不包含text/html
,并且最后始终有*/*
。当Spring收到来自IE的请求时,它看不到任何内容类型直接等于我的控制器生成的内容类型,但是,锁定到*/*
通配符,它(正确地)决定两个映射都适用。
面对多个匹配的处理程序映射,Spring(在RequestMappingHandlerMapping bean中)对映射进行排序,基本上等于字典顺序,选择第一个映射,然后继续。从我的角度来看,问题在于此流程会优先application/json
优先于text/html
。 除非客户专门请求text/html
,否则我宁愿返回application/json
- 这样,我就可以向像IE这样的愚蠢客户端提供HTML,为内容类型精明的客户端提供JSON喜欢我API的用户。
有没有人知道这样做的方法,不需要扩展RequestMappingHandlerMapping来对处理程序进行不同的排序?你有任何简单的解决方法吗?
注意:我已尝试按照on the Spring blog所述在ContentNegotiationManager中设置默认内容类型。它没有解决我的问题,因为该设置仅在未指定Accept标头时生效。
答案 0 :(得分: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/html
转到fooHTML()
application/json
转到fooJSON()
*/*
转到fooHTML()
406 - Not Acceptable
错误答案 1 :(得分:1)
我发现解决此问题的一种方法是在您的请求映射中添加一个ALL mimetype,以提供响应的HTML版本。
@RequestMapping(value="/foo", produces={"text/html", "*/*"})
public String fooHTML() {
// ...
}
这意味着HTML响应适用于任何以前未映射的mime类型。在我的情况下,需要这种行为,但如果你需要返回406(不可接受)的响应代码,那么这对你来说不会有用。