Существует несколько вариантов использования для установки кодов состояния HTTP в веб-службе REST, и по крайней мере один из них не был достаточно документирован в существующих ответах (т. Е. Когда вы используете автоматическую магическую сериализацию JSON / XML с использованием JAXB, и вы хотитевернуть объект для сериализации, но также код состояния, отличный от значения по умолчанию 200).
Итак, позвольте мне попытаться перечислить различные варианты использования и решения для каждого из них:
1,Код ошибки (500, 404, ...)
Наиболее распространенный вариант использования, когда вы хотите вернуть код состояния, отличный от 200 OK
, - это когда возникает ошибка.
Например:
- объект запрашивается, но он не существует (404)
- запрос семантически неверен (400)
- пользователь не авторизован (401)
- существует проблема с подключением к базе данных (500)
- и т. Д.
a) Сгенерировать исключение
В этом случаеЯ думаю, что самый чистый способ решения проблемы - это исключение.Это исключение будет обработано ExceptionMapper
, который преобразует исключение в ответ с соответствующим кодом ошибки.
Вы можете использовать значение по умолчанию ExceptionMapper
, которое предварительно сконфигурировано с Джерси (и я полагаю,то же самое с другими реализациями) и выбросить любой из существующих подклассов javax.ws.rs.WebApplicationException
.Это предопределенные типы исключений, которые предварительно сопоставляются с различными кодами ошибок, например:
- BadRequestException (400)
- InternalServerErrorException (500)
- NotFoundException(404)
и т. Д.Вы можете найти список здесь: API
Кроме того, вы можете определить свои собственные исключения и классы ExceptionMapper
и добавить эти сопоставители в Джерси с помощью аннотации @Provider
( источник этого примера ):
public class MyApplicationException extends Exception implements Serializable
{
private static final long serialVersionUID = 1L;
public MyApplicationException() {
super();
}
public MyApplicationException(String msg) {
super(msg);
}
public MyApplicationException(String msg, Exception e) {
super(msg, e);
}
}
Поставщик:
@Provider
public class MyApplicationExceptionHandler implements ExceptionMapper<MyApplicationException>
{
@Override
public Response toResponse(MyApplicationException exception)
{
return Response.status(Status.BAD_REQUEST).entity(exception.getMessage()).build();
}
}
Примечание: вы также можете написать ExceptionMappers для существующих типов исключений, которые вы используете.
b) Использование построителя ответов
Другой способ установить код состояния - использовать построитель Response
для создания ответа с предполагаемым кодом.
В этом случаетип возврата вашего метода должен быть javax.ws.rs.core.Response
.Это описано в различных других ответах, таких как принятый ответ его самого, и выглядит так:
@GET
@Path("myresource({id}")
public Response retrieveSomething(@PathParam("id") String id) {
...
Entity entity = service.getById(uuid);
if(entity == null) {
return Response.status(Response.Status.NOT_FOUND).entity("Resource not found for ID: " + uuid).build();
}
...
}
2.Успешно, но не 200
Другой случай, когда вы хотите установить статус возврата, это когда операция прошла успешно, но вы хотите вернуть код успеха, отличный от 200, вместе с содержимым, которое вы возвращаете в теле..
Частый случай использования - это когда вы создаете новую сущность (POST
запрос) и хотите вернуть информацию об этой новой сущности или, возможно, о самой сущности вместе с 201 Created
кодом состояния.
Одним из подходов является использование объекта ответа, как описано выше, и установка тела запроса самостоятельно.Однако, делая это, вы теряете возможность использовать автоматическую сериализацию в XML или JSON, предоставляемую JAXB.
Это оригинальный метод, возвращающий объект сущности, который будет сериализован в JSON JAXB:
@Path("/")
@POST
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public User addUser(User user){
User newuser = ... do something like DB insert ...
return newuser;
}
Это вернет JSON-представление вновь созданного пользователя, но статус возврата будет 200, а не 201.
Теперь проблема в том, хочу ли я использовать компоновщик Response
для установкикод возврата, я должен вернуть объект Response
в моем методе.Как мне по-прежнему возвращать объект User
для сериализации?
a) Установить код в ответе сервлета
Один из способов решить эту проблему - получить объект запроса сервлета и установитьКод ответа вручную мы сами, как показано в ответе Гаретт Уилсон:
@Path("/")
@POST
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public User addUser(User user, @Context final HttpServletResponse response){
User newUser = ...
//set HTTP code to "201 Created"
response.setStatus(HttpServletResponse.SC_CREATED);
try {
response.flushBuffer();
}catch(Exception e){}
return newUser;
}
Метод по-прежнему возвращает объект сущности, а код состояния будет 201.
Обратите внимание, что для того, чтобы это сработало, мне пришлось сбросить ответ.Это неприятный всплеск низкоуровневого кода API сервлета в нашем замечательном ресурсе JAX_RS, и, что еще хуже, после этого заголовки становятся неизменяемыми, поскольку они уже были отправлены по проводам.объект ответа с сущностью
Лучшее решение в этом случае состоит в том, чтобы использовать объект Response и настроить сериализацию сущности на этом объекте ответа.Было бы неплохо сделать объект Response универсальным для указания типа объекта полезной нагрузки в этом случае, но в настоящее время это не так.
@Path("/")
@POST
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public Response addUser(User user){
User newUser = ...
return Response.created(hateoas.buildLinkUri(newUser, "entity")).entity(restResponse).build();
}
В этом случае мы используем созданный методКласс построителя ответов для установки кода состояния на 201. Мы передаем объект-сущность (пользователя) в ответ через метод entity ().
В результате получается, что HTTP-код равен 401, как мы и хотели,и тело ответа - тот же самый JSON, который был у нас, когда мы только что вернули объект User.Он также добавляет заголовок местоположения.
Класс Response имеет ряд методов построения для различных состояний (stati?), Таких как:
Response.accepted () Response.ok () Response.noContent () Response.notAcceptable ()
Примечание: объект hateoas - это вспомогательный класс, который я разработал для создания URI ресурсов.Вам нужно будет придумать здесь свой собственный механизм;)
Вот и все.
Надеюсь, этот длинный ответ кому-нибудь поможет:)