Как обращаться с accept-параметрами при разработке приложения jax-rs
чтобы иметь дело с различными версиями типа контента, я пытаюсь использовать accept-параметры заголовков" Accept*" (RFC 2616).
Accept: application/vnd.mycompany.mytype;version=2 , application/vnd.mycompany.mytype;version=1;q=0.1
проблема в том, что аннотации Jax-RS не поддерживают параметры Accept...
@GET
@Produces("application/vnd.test;version=1")
public Response test1() {
return Response.ok("Version 1", "application/vnd.test").build();
}
@GET
@Produces("application/vnd.test;version=2")
public Response test2() {
return Response.ok("Version 2", "application/vnd.test").build();
}
приводит к исключению конфликта типов носителей:
Producing media type conflict. The resource methods public javax.ws.rs.core.Response test.resources.TestResource.test2() and public javax.ws.rs.core.Response test.resources.TestResource.test1() can produce the same media type
возможно, это исключение связано только с моей структурой JAX-RS (Джерси), но я боюсь, что это связано с JSR311 что не ясно принимать параметры.
к настоящему времени я использую content-types, которые содержат версию в своих именах, но я нашел это решение довольно уродливо.
@GET
@Produces("application/vnd.test-v1")
public Response test() {
return Response.ok("Version 1", "application/vnd.test-v1").build();
}
у вас есть какие-либо идеи о том, как бороться с Accept-параметры ?
редактировать
думаю, я недостаточно ясно выразился. Я хочу автоматически перенаправить запрос на определенные методы. Эти методы являются версионными и соответствуют определенной версии возвращаемого тип содержимого. Текущая реализация JAX-RS не позволяет мне использовать accept-parameters для маршрутизации запроса (к соответствующему методу).
greenkode предлагает мне управлять version
accept-параметр в методе диспетчеризации (используя @HeaderParam("Accept")
).
Это решение в конечном итоге приведет к перезаписи логики отрицания содержимого, которая встроена в структуру (и описана в JSR 311).
что я могу сделать, чтобы использовать логику accept-parameter и content-negociation от JAX-RS ?
возможно, решение заключается в использовании другой структуры (я работал только с Джерси сейчас). Но я не знаю, какой именно.
3 ответов
спецификация JAX-RS не явно укажите что-нибудь об игнорировании параметров заголовка Accept. Но единственный параметр, для которого обращение наверняка определена качество (q). Это возможная область для улучшения, поскольку она, по-видимому, привела к двусмысленности (или прямой баггичности) в реализации Джерси. Текущая версия Джерси (1.17) не учитывает параметры заголовка Accept при сопоставлении входящих запросов к методам ресурсов, поэтому вы получаете сообщение об ошибке:
строгий: Производящ тип конфликт средств массовой информации. Ресурсные методы ...
на ресурсе:
@GET
@Produces("application/vnd.test;version=1")
public Response test1() {
return Response.ok("Version 1", "application/vnd.test").build();
}
@GET
@Produces("application/vnd.test;version=2")
public Response test2() {
return Response.ok("Version 2", "application/vnd.test").build();
}
похоже, что Джерси выполняет проверку "уникальности" на основе заголовка Accept "type/subtype", полностью опуская любые параметры. Это может быть подтверждено тестированием с различными парами заголовков на "соответствующих" методах ресурсов:
Resource 1 Resource 2 ---------------------------------------- text/html;q=0.4 text/html;q=0.8 text/html text/html;q=0.2 text/html text/html;qs=1.4 text/html;qs=1.4 text/html;qs=1.8 text/html;level=1 text/html;level=2 text/html;foo=bleh text/html;bar=23
все плохо с той же ошибкой. Если бы было сделано предположение, что когда-либо отправляется только параметр качества, тогда имело бы смысл сопоставлять только "тип/подтип", потому что такой запрос бессмыслен:
Accept: text / html;q=0.8, text/html; q=0.4, text/html
Ака качество параметры имеют смысл только тогда, когда вы имеете дело с mix возможных типов контента. Однако такое ограниченное сопоставление не выполняется, когда некачественные параметры или дополнительные параметры отправляются:
Accept: text / html; version=4.0; q=0.8, text / html; version=3.2; q=0.4
Итак, каковы возможные решения?
- перехватить запрос высокого уровня на основе "тип / подтип", а затем маршрут к более подходящему методу (вы указали, что не хотите этого делать)
- измените ожидаемые заголовки. Например ' application/vnd.mycompany.тип mytype+П2' и 'приложение/донгов.mycompany.тип mytype+В1'. Никаких других изменений не потребуется, и вы можете продолжать использовать Джерси
- рамки переключателя. RESTEasy случается обрабатывать ваш сценарий с легкостью.
С RESTEasy и ресурсом:
@Path("/content/version")
public class ContentVersionResource {
@GET
@Produces("application/vnd.test;version=1")
public Response test1() {
return Response.ok("Version 1", "application/vnd.test").build();
}
@GET
@Produces("application/vnd.test;version=2")
public Response test2() {
return Response.ok("Version 2", "application/vnd.test").build();
}
}
успешное совпадение выполняется со следующим заголовком Accept:
Accept: application / vnd.test; version=1; q=0.3, application / vnd.тест; версия=2; q=0,5
Ответ: Версия 2
и так:
Accept: application / vnd.test; version=1; q=0.5, application / vnd.тест; версия=2; q=0,3
Ответ: Вариант 1
вы можете скачать и протестировать с помощью этого пример проекта. Git, Maven и JBoss 7.X требуется
если я ничего не упускаю. JAX-RS поддерживает параметры Accept. посмотри @Consumes("*/*")
Примечание. Кроме того, исключение, которое вы получаете с конфликтом типа носителя, происходит потому, что у вас есть два GET
методы с тем же url-адресом. аннотировать test2 на() метод с @Path("test2")
, а затем отправить ваш GET
запрос на url/test2 вместо этого. это должно избавиться от этой ошибки.
редактировать
вы можете ввести значение Accept
заголовок с помощью @HeaderParams
. Вот пример того, что я сделал.
@Path("/conneg")
public class ConnNeg {
@GET
@Produces("application/vnd.test;version=1")
public Response test1(@HeaderParam("Accept") String header) {
System.out.println(header);
return Response.ok("Version 1", "application/vnd.test").build();
}
}
запрос
Accept: application / vnd.test; version=2, application / vnd.тест; Версия=1; q=0,1
выводит
application / vnd.test; version=2, application / vnd.тест; Версия=1; q=0,1
вы можете обрабатывать его вручную. Это то, что ты ищешь?
С Jersey framework заголовок Accept HTTP-запроса объявил, что является наиболее приемлемым. Если класс ресурсов способен создавать более одного типа носителя MIME, то выбранный метод ресурса будет соответствовать наиболее приемлемому типу носителя, объявленному клиентом. В вашем случае, если заголовок accept
Accept: application/vnd.mycompany.mytype;version=2
затем будет вызван метод test1 ().
Если это
Accept: application/vnd.mycompany.mytype;q=0.9 version=2, application/vnd.mycompany.mytype;version=1
вторая будет называемый.
в одном объявлении @Produces может быть объявлено несколько типов носителей, например:
@GET
@Produces({"application/vnd.mycompany.mytype; version=2", "application/vnd.mycompany.mytype; version=1"})
public Response test() {
return Response.ok("").build();
}
тест (9 метод будет вызван, если любой из 2-х медиатипов является приемлемым. если оба варианта приемлемы, будет задействован первый.
надеюсь, что это помогает!