Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
550 views
in Technique[技术] by (71.8m points)

rest - HTTP content negotiation conflicts in JAX-RS/Jersey?

I am enjoying the auto HTTP content negotiation of JAX-RS (specifically Jersey), i.e. its ability to route my resources by "Accept" and/or "Content-Type" headers. But I'm finding that sometimes it doesn't give me enough control when there is a conflict.

For example, consider the following endpoints:

@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);
    }
}

I will get different results between Firefox and Chrome. Firefox will map to the HTML endpoint while Chrome will trigger the XML endpoint when I navigate each to the endpoint URL. The difference between them is the order of the listed MIME types in their Accept headers. Chrome sends the following:

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

Versus in Firefox it lists HTML first:

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

Seems logical that it would match the first entry when all are weighted the same. But in my case I am getting the different results than I want so it would be nice to determine a better method for tie-breaking.

My question: short of injecting header information into these methods and performing the media type processing myself, is there a way to "tweak the weights" so to speak in the event of a tie? For instance, can I tell it to always trump XML with HTML? My RESTful clients are very explicit about what type they want back but browsers are notoriously sloppy with Accept headers. (Personally I think they should weight HTML slightly above XML as this is what users expect but it's a little late for that.)

Alternatively, can I perform my own custom content negotiation only once in some centralized location? I'm not opposed to writing this logic out manually but not if it means applying it to every single instance of my resources. Does JAX-RS have some concept of adding a filter to the pipeline to tweak requests before they are routed?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

There is a mechanism in Jersey to override the relative degree of preference from the HTTP Accept header. Just add a parameter "qs" to the @Produces annotation that you want to take precedence. In your case: @Produces("text/html;qs=2") Note that the http "q" values range from 0-1 and the Jersey "qs" values should be >= 1 (1 is default).

(I learned about this from this source, and I wrote a little note for myself here)


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...