Подтвердить что ты не робот

Джерси: @Consumes не совсем работает, когда тип контента не задан

Я пытаюсь понять, как работает @Consumes здесь.

У меня есть упрощенный ресурс, который выглядит как ниже, и я хочу, чтобы этот ресурс потреблял "application/vnd.myApp + xml".

@Path("/app")
@Consumes("application/vnd.myApp+xml")
@Produces("application/vnd.myApp+xml")
public class AppResource {
    @POST
    public Response postStuff() {
        ...
    }
}

У меня есть следующие тестовые коды: -

public class AppResourceTest extends JerseyTest {
    @Test
    public void testApp() {
        // #1: Works fine
        ClientResponse response = resource().path("app")
                    .accept("application/vnd.myApp+xml")
                    .post(ClientResponse.class);

        ...

        // #2: Throws a 415 Unsupported Media Type
        ClientResponse response = resource().path("app")
                    .accept("application/vnd.myApp+xml")
                    .type("text/plain")
                    .post(ClientResponse.class);

        ...

        // #3: Works fine
        ClientResponse response = resource().path("app")
                    .accept("application/vnd.myApp+xml")
                    .type("application/vnd.myApp+xml")
                    .post(ClientResponse.class);

        ...
    }
}

Из 3-х тестов выше, # 2 и # 3 работают, как ожидалось.

Что касается №1, если я не устанавливаю тип содержимого, почему он тоже не бросает 415?

4b9b3361

Ответ 1

На основе @Consumes api (http://jsr311.java.net/nonav/releases/1.0/javax/ws/rs/Consumes.html) и спецификации типа HTTP (http://www.w3.org/Protocols/rfc2616/rfc2616-sec7.html#sec7.2.1) в сочетании с поведением, которое вы видите, я думаю, что безопасно завершить следующую реализацию Джерси:

Если Content-Type не установлен клиентом, то Джерси не имеет значения по умолчанию, но позволяет ему передавать любые/все @-консультации аннотации.

Когда для URI задано несколько @Consumes {разных типов}, и клиент НЕ установил Content-Type, то Джерси по умолчанию будет использовать аннотацию @Consumes или первый тип в списке допустимых типов.

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

В заключение @Consumes действует только как фильтр, если и ТОЛЬКО, если клиент устанавливает Content-Type, иначе Джерси попытается найти наилучшее соответствие. Это соответствует спецификации HTTP:

Любое сообщение HTTP/1.1, содержащее тело-сущность, ДОЛЖНО включать поле заголовка Content-Type, определяющее тип носителя этого тела. Если и только если тип материала не задан поле Content-Type, получатель МОЖЕТ попытаться угадать тип носителя путем проверки его содержимого и/или расширений имен URI, используемых для идентификации ресурса. Если тип носителя остается неизвестным, получатель ДОЛЖЕН рассматривать его как тип "приложение/октет-поток".

Если цель состоит в том, чтобы @Consumes выступала в качестве белого списка, тогда фильтр сервлета можно использовать для по умолчанию для Content-Type для запросов, где ни один не установлен.

Ответ 2

На основе документов, которые, кажется, используют @Consumes на уровне класса, явно не переопределяет определения уровня метода (который по умолчанию равен */*), поэтому разумно, что он может работать аддитивным образом...

Пробовали ли вы применить те же @Consumes к определению метода?

Ответ 3

Вы должны указать тип, например:

ClientResponse res =
    service.path("accounts")
        .type("application/vnd.dsu.account+json")
        .post(ClientResponse.class,ent);