Конфликты согласования содержимого 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 ответа
Как говорится в Руководстве пользователя Джерси:
Если оба одинаково приемлемы, тогда будет выбран первый, потому что это происходит первым.
Из того, что я знаю, это оставляет вам две возможности / хаки:
Добавьте расширение файла к вашим URI, чтобы переопределить заголовок Accept.
Напишите фильтр сервлетов, который перезаписывает заголовок Accept для этих пользовательских агентов.
В Джерси существует механизм, позволяющий переопределить относительную степень предпочтения заголовка HTTP Accept. Просто добавьте параметр "qs" в аннотацию @Produces, который вы хотите иметь приоритет. В твоем случае:@Produces("text/html;qs=2")
Обратите внимание, что значения http "q" находятся в диапазоне от 0 до 1, а значения "qs" на Джерси должны быть>= 1 (1 по умолчанию).
(Я узнал об этом из этого источника, и я написал небольшую заметку для себя здесь)