Как обращаться с 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-х медиатипов является приемлемым. если оба варианта приемлемы, будет задействован первый.

надеюсь, что это помогает!