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

Мне нравится автоматическое согласование 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 некоторая концепция добавления фильтра в конвейер для настройки запросов до их маршрутизации?


person mckamey    schedule 09.03.2011    source источник


Ответы (2)


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

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

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

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

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

person Christoph Metzendorf    schedule 10.03.2011
comment
Спасибо, фильтр сервлетов работает отлично. Интересно, что я нашел парня, который сочетает в себе два ваших предложения; он пишет фильтр сервлета, чтобы иметь возможность заменить расширение файла заголовком Accept. Однако в его коде есть опечатка, поскольку его проверка заголовка чувствительна к регистру. Тем не менее интересно: zienit.nl /блог/2010/01/отдых/ - person mckamey; 10.03.2011
comment
Вот модифицированный фильтр сервлетов, который добавляет поддержку расширений файлов и исправляет порядок заголовков WebKit Accept. gist.github.com/865216 - person mckamey; 11.03.2011
comment
@mckamey эти дополнения в комментариях, которые вы написали, должны быть превращены в ответ, потому что комментарии не предназначены для вечной жизни. - person hiergiltdiestfu; 27.01.2017

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

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

person Erik    schedule 04.04.2011
comment
Я обнаружил, что это решение имеет некоторые проблемы с ним. Прежде всего, он передает ;qs=2 клиенту в заголовке Content-Type. Но проблема заключалась в том, что он слишком тяжелый. Например, запросы jQuery с Accept: application/json, text/javascript, /; q=0,01, но с text/html;qs=2 и application/json Джерси отправляет HTML через JSON. - person mckamey; 16.04.2011