Конфликты согласования содержимого HTTP в JAX-RS/Jersey?

Я наслаждаюсь автоматическим согласованием содержимого HTTP JAX-RS (в частности, Джерси), т. Е. Возможностью маршрутизации моих ресурсов по заголовкам "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);
    }
}

Я получу разные результаты между Firefox и Chrome. Firefox отобразит конечную точку HTML, а Chrome запустит конечную точку XML, когда я перейду к URL-адресу конечной точки. Разница между ними заключается в порядке перечисления типов MIME в их заголовках Accept. 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

В отличие от 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

Кажется логичным, что он будет соответствовать первой записи, когда все будут взвешены одинаково. Но в моем случае я получаю результаты, отличные от тех, которые мне нужны, поэтому было бы неплохо выбрать лучший метод для разрыва связей.

Мой вопрос: если не вводить информацию заголовка в эти методы и самостоятельно выполнять обработку типов носителей, есть ли способ, так сказать, "подправить вес" в случае ничьей? Например, могу ли я сказать, что всегда бить XML с HTML? Мои клиенты RESTful очень четко говорят, какой тип они хотят вернуть, но браузеры общеизвестно неаккуратны с заголовками Accept. (Лично я думаю, что они должны весить HTML немного выше XML, поскольку это то, что пользователи ожидают, но для этого уже немного поздно.)

В качестве альтернативы, я могу выполнить свое собственное согласование контента только один раз в каком-то централизованном месте? Я не против написания этой логики вручную, но не в том случае, если это означает применение ее к каждому экземпляру моих ресурсов. Есть ли у JAX-RS какая-то концепция добавления фильтра в конвейер для настройки запросов перед их маршрутизацией?

2 ответа

Решение

Как говорится в Руководстве пользователя Джерси:

Если оба одинаково приемлемы, тогда будет выбран первый, потому что это происходит первым.

Из того, что я знаю, это оставляет вам две возможности / хаки:

  1. Добавьте расширение файла к вашим URI, чтобы переопределить заголовок Accept.

  2. Напишите фильтр сервлетов, который перезаписывает заголовок Accept для этих пользовательских агентов.

В Джерси существует механизм, позволяющий переопределить относительную степень предпочтения заголовка HTTP Accept. Просто добавьте параметр "qs" в аннотацию @Produces, который вы хотите иметь приоритет. В твоем случае:@Produces("text/html;qs=2")Обратите внимание, что значения http "q" находятся в диапазоне от 0 до 1, а значения "qs" на Джерси должны быть>= 1 (1 по умолчанию).

(Я узнал об этом из этого источника, и я написал небольшую заметку для себя здесь)

Другие вопросы по тегам