JAX-RS/Jersey中的HTTP内容协商冲突?

mck*_*mey 6 rest jax-rs jersey content-negotiation http-headers

我很享受JAX-RS(特别是Jersey)的自动HTTP内容协商,即它能够通过"Accept"和/或"Content-Type"标头来路由我的资源.但是我发现有时它会在发生冲突时给我足够的控制权.

例如,请考虑以下端点:

@Path("/order")
public class OrderController {

    @GET
    @Path("{orderID: \\d+}")
    @Produces("text/html")
    public View getOrderView(@PathParam("orderID") long id) {
        Order order = this.getOrderData(id);
        return new OrderView(order);
    }

    @GET
    @Path("{orderID: \\d+}")
    @Produces({"application/json", "application/xml"})
    public Order getOrderData(@PathParam("orderID") long id) {
        return new OrderService.findOrder(id);
    }
}
Run Code Online (Sandbox Code Playgroud)

我会在Firefox和Chrome之间得到不同的结果.Firefox将映射到HTML端点,而当我将每个端点URL导航到端点URL时,Chrome将触发XML端点.它们之间的区别在于它们的Accept标头中列出的MIME类型的顺序.Chrome发送以下内容:

User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.107 Safari/534.13
Accept: application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5
Run Code Online (Sandbox Code Playgroud)

与Firefox相比,它首先列出了HTML:

User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Run Code Online (Sandbox Code Playgroud)

似乎逻辑上,当所有加权相同时,它将匹配第一个条目.但在我的情况下,我得到的结果与我想要的不同,所以确定更好的打破方法会更好.

我的问题:如果没有将标题信息注入这些方法并自己执行媒体类型处理,有没有办法"调整权重",以便在出现平局时说话?例如,我可以告诉它总是用HTML来胜过XML吗?我的RESTful客户端非常清楚他们想要什么类型,但浏览器众所周知地使用Accept标头.(就我个人而言,我认为他们应该将HTML重量略高于XML,因为这是用户所期望的,但这有点晚了.)

或者,我可以在某个集中位置执行自己的自定义内容协商吗?我并不反对手动编写这个逻辑,但如果它意味着将它应用于我的每个资源实例都不会.JAX-RS是否有一些向管道添加过滤器的概念,以便在路由之前调整请求?

Eri*_*rik 10

Jersey中有一种机制可以覆盖HTTP Accept标头的相对优先级.只需将参数"qs"添加到要优先使用的@Produces注释中.在您的情况下: @Produces("text/html;qs=2") 请注意,http"q"值的范围为0-1,泽西岛"qs"值应> = 1(默认值为1).

(我从这个来源了解到这一点,我在这里为自己写了一个小纸条)

  • 我发现这个解决方案有一些问题.首先,它将"; qs = 2"一直传递到Content-Type标头中的客户端.但是交易破坏者的重量太大了.例如,jQuery请求"Accept:application/json,text/javascript,*/*; q = 0.01"但是"text/html; qs = 2"和"application/json",Jersey通过JSON发送HTML. (3认同)

Chr*_*orf 1

正如泽西岛用户指南所述:

如果两者同样可以接受,则将选择前者,因为它先发生。

据我所知,这给你留下了两种可能性/技巧:

  1. 将文件扩展名附加到 URI 以覆盖 Accept 标头

  2. 编写一个 Servlet 过滤器来覆盖这些用户代理的 Accept 标头