您的位置:首页 > 理论基础 > 计算机网络

JAX-RS入门 八: HTTP响应

2014-02-24 13:15 288 查看
首先先看一下HTTP中定义的响应码及其意义:

响应码含义
100继续
101分组交换协议
200OK
201被创建
202被采纳
203非授权信息
204无内容
205重置内容
206部分内容
300多选项
301永久地传递
302找到
303参见其他
304未改动
305使用代理
307暂时重定向
400错误请求
401未授权
402要求付费
403禁止
404未找到
405不允许的方法
406不被采纳
407要求代理授权
408请求超时
409冲突
410过期的
411要求的长度
412前提不成立
413请求实例太大
414请求URL太大
415不支持的媒体类型
416无法满足的请求范围
417失败的预期
500内部错误
501未被使用
502网关错误
503不可用的服务
504网关超时
505HTTP版本未被支持
一、成功

从 200 到 399 为成功码,表示请求处理成功。

如果方法返回值不为null,则返回码是 200;如果返回值为 null 或者为 void,则返回码为 204,表示无内容。

二、错误

从 400 到 599 表示处理错误。

例如 404表示网页未找着;如果请求的期望的返回交换类型不对,则返回 406,表示不可接爱;如果请求的方法未找着,则返回 405,表示方法不允许,这个返回结果对于HEAD和OPTIONS请求方法例外,对于HEAD会试图去查找能处理相同URI的GET方法;对于OPTION,会返回一些自动生成的信息。

三、复杂的响应

对于不能简单处理的返回信息,则可以返回javax.ws.rs.core.Response对象:

Java代码



public abstract class Response {

public abstract Object getEntity();

public abstract int getStatus();

public abstract MultivaluedMap<String, Object> getMetadata();

...

}

Response对象不能直接创建,需要通过javax.ws.rs.core.Response.ResponseBuilder来创建:

Java代码



public abstract class Response {

...

public static ResponseBuilder status(Status status) {...}

public static ResponseBuilder status(int status) {...}

public static ResponseBuilder ok() {...}

public static ResponseBuilder ok(Object entity) {...}

public static ResponseBuilder ok(Object entity, MediaType type) {...}

public static ResponseBuilder ok(Object entity, String type) {...}

public static ResponseBuilder ok(Object entity, Variant var) {...}

public static ResponseBuilder serverError() {...}

public static ResponseBuilder created(URI location) {...}

public static ResponseBuilder noContent() {...}

public static ResponseBuilder notModified() {...}

public static ResponseBuilder notModified(EntityTag tag) {...}

public static ResponseBuilder notModified(String tag) {...}

public static ResponseBuilder seeOther(URI location) {...}

public static ResponseBuilder temporaryRedirect(URI location) {...}

public static ResponseBuilder notAcceptable(List<Variant> variants) {...}

public static ResponseBuilder fromResponse(Response response) {...}

...

}

ResponseBuilder是一个用来创建单个Response实例的工厂类, 首先将要创建的response对象的状态存起来,最后当状态设置完成了,就使用builder去初始化Response:

Java代码



public static abstract class ResponseBuilder {

public abstract Response build();

public abstract ResponseBuilder clone();

public abstract ResponseBuilder status(int status);

public ResponseBuilder status(Status status) {...}

public abstract ResponseBuilder entity(Object entity);

public abstract ResponseBuilder type(MediaType type);

public abstract ResponseBuilder type(String type);

public abstract ResponseBuilder variant(Variant variant);

public abstract ResponseBuilder variants(List<Variant> variants);

public abstract ResponseBuilder language(String language);

public abstract ResponseBuilder language(Locale language);

public abstract ResponseBuilder location(URI location);

public abstract ResponseBuilder contentLocation(URI location);

public abstract ResponseBuilder tag(EntityTag tag);

public abstract ResponseBuilder tag(String tag);

public abstract ResponseBuilder lastModified(Date lastModified);

public abstract ResponseBuilder cacheControl(CacheControl cacheControl);

public abstract ResponseBuilder expires(Date expires);

public abstract ResponseBuilder header(String name, Object value);

public abstract ResponseBuilder cookie(NewCookie... cookies);

}

例如:

Java代码



@Path("/textbook")

public class TextBookService {

@GET

@Path("/restfuljava")

@Produces("text/plain")

public Response getBook() {

String book = ...;

ResponseBuilder builder = Response.ok(book);

builder.language("fr").header("Some-Header", "some value");

return builder.build();

}

}

四、Cookie

JAX-RS使用了一个简单的类去表示一个cookie值,它就是javax.ws.rs.core.NewCookie:

Java代码



public class NewCookie extends Cookie {

public static final int DEFAULT_MAX_AGE = −1;

public NewCookie(String name, String value) {}

public NewCookie(String name, String value, String path,

String domain, String comment,

int maxAge, boolean secure) {}

public NewCookie(String name, String value, String path,

String domain, int version, String comment,

int maxAge, boolean secure) {}

public NewCookie(Cookie cookie) {}

public NewCookie(Cookie cookie, String comment,

int maxAge, boolean secure) {}

public static NewCookie valueOf(String value)

throws IllegalArgumentException {}

public String getComment() {}

public int getMaxAge() {}

public boolean isSecure() {}

public Cookie toCookie() {}

}

要返回Cookie,只需要传入它到Response中:

Java代码



@GET

public Response get() {

NewCookie cookie = new NewCookie("key", "value);

ResponseBuilder builder = Response.ok("hello", "text/plain");

return builder.cookies(cookie).build();

}

五、状态类别

除了直接写数据外,JAX-RS定义了一个状态值的枚举类别:

Java代码



public enum Status {

OK(200, "OK"),

CREATED(201, "Created"),

ACCEPTED(202, "Accepted"),

NO_CONTENT(204, "No Content"),

MOVED_PERMANENTLY(301, "Moved Permanently"),

SEE_OTHER(303, "See Other"),

NOT_MODIFIED(304, "Not Modified"),

TEMPORARY_REDIRECT(307, "Temporary Redirect"),

BAD_REQUEST(400, "Bad Request"),

UNAUTHORIZED(401, "Unauthorized"),

FORBIDDEN(403, "Forbidden"),

NOT_FOUND(404, "Not Found"),

NOT_ACCEPTABLE(406, "Not Acceptable"),

CONFLICT(409, "Conflict"),

GONE(410, "Gone"),

PRECONDITION_FAILED(412, "Precondition Failed"),

UNSUPPORTED_MEDIA_TYPE(415, "Unsupported Media Type"),

INTERNAL_SERVER_ERROR(500, "Internal Server Error"),

SERVICE_UNAVAILABLE(503, "Service Unavailable");

public enum Family {

INFORMATIONAL, SUCCESSFUL, REDIRECTION,

CLIENT_ERROR, SERVER_ERROR, OTHER

}

public Family getFamily()

public int getStatusCode()

public static Status fromStatusCode(final int statusCode)

}

每个Status的值都关联的到一个特定HTTP的返回值族,这个族由Status.Family标识。例如 100范围的值被认识是信息性的;200范围的是成功;300范围的也是成功,但是被重定向的;400是client错误;500是服务器错误。

Response.status()和ResponseBuilder.status()都接受一个Status值,例如:

Java代码



@DELETE

Response delete() {

...

return Response.status(Status.GONE).build();

}

六、javax.ws.rs.core.GenericEntity

当处理Response的返回对象(entity)时,如果是一个类似于MessageBodyWriter这样的支持泛型的对象,则问题来了: isWriteable()方法需要有泛弄的信息。然后不幸的是java的泛型信息只存在编译时,不存在运行时,因此没有一个简单的方法可以得到在运行时得到泛型的信息,因此MessageBodyWriter不知道如何输出对象。

为了解决这个问题,JAX-RS提供了一个帮助类 javax.ws.rs.core.GenericEntity 。例如:

Java代码



@GET

@Produces("application/xml")

public Response getCustomerList() {

List<Customer> list = new ArrayList<Customer>();

list.add(new Customer(...));

GenericEntity entity = new GenericEntity<List<Customer>>(list){};

return Response.ok(entity);

}

GenericEntity也是一个泛型模板,只需要将输出entity的泛型信息加到它上,并且把对象做为一个参数传入即可。

七、javax.ws.rs.WebApplicationException

WebApplicationException是一个内置、非检测异常,支持传入Response对象或者状态码:

Java代码



public class WebApplicationException extends RuntimeException {

public WebApplicationException() {...}

public WebApplicationException(Response response) {...}

public WebApplicationException(int status) {...}

public WebApplicationException(Response.Status status) {...}

public WebApplicationException(Throwable cause) {...}

public WebApplicationException(Throwable cause,

Response response) {...}

public WebApplicationException(Throwable cause, int status) {...}

public WebApplicationException(Throwable cause,

Response.Status status) {...}

public Response getResponse() {...]

}

当JAX-RS碰到一个WebApplicationException抛出时,它就捕获这个异常,调用它的getResponse()方法去获取Response,发回给client端。 如果应用以一个状态码或者Response初始化了WebApplicationException,则这个状态码或者Response将被用来创建真正的HTTP响应;或者,会直接返回 500, “Internal Server Error“给客户端,例如:

Java代码



@Path("/customers")

public class CustomerResource {

@GET

@Path("{id}")

@Produces("application/xml")

public Customer getCustomer(@PathParam("id") int id) {

Customer cust = findCustomer(id);

if (cust == null) {

throw new WebApplicationException(Response.Status.NOT_FOUND);

}

return cust;

}

}

这里如果没找着客户,会返回404错误

八、错误匹配

应用中可能有各种各样的,来自应用或者第三方包的异常,如果仅依赖于容器提供的错误处理方式,则可能灵活度不够: 捕获这些异常,然后包装到WebApplicationException中会让人觉得相当乏味。

这里的另外一种选择就是使用javax.ws.rs.ext.ExceptionMapper,这个对象知道怎么匹配一个抛出的异常到一个Repsonse对象上:

Java代码



public interface ExceptionMapper<E extends Throwable> {

Response toResponse(E exception);

}

例如对于JPA有EntityNotFoundException:

Java代码



@Provider

public class EntityNotFoundMapper

implements ExceptionMapper<EntityNotFoundException> {

public Response toResponse(EntityNotFoundException e) {

return Response.status(Response.Status.NOT_FOUND).build();

}

}

注: ExceptionMapper的实现,必须加上@Provider注释

ExceptionMapper也支持异常层级关系,例如A 继承 B,如果找不到A的mapper,则会向上查找B的mapper。

最后ExceptionMapper使用JAX-RS的deployment API进行注册,可以用Application.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: