48.5.2. 超时和超时处理程序
概述
异步处理模型还支持在 REST 调用时实现超时。默认情况下,超时会导致将 HTTP 错误响应发送到客户端。但是,您还可以选择注册超时处理器回调,它可让您自定义对超时事件的响应。
设置没有处理程序的超时示例
要定义简单的调用超时,但不指定 timeout 处理程序,在 AsyncResponse
对象中调用 setTimeout
方法,如下例所示:
// Java // Java ... import java.util.concurrent.TimeUnit; ... import javax.ws.rs.GET; import javax.ws.rs.NotFoundException; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.container.AsyncResponse; import javax.ws.rs.container.Suspended; import javax.ws.rs.container.TimeoutHandler; @Path("/bookstore") public class BookContinuationStore { ... @GET @Path("/books/defaulttimeout") public void getBookDescriptionWithTimeout(@Suspended AsyncResponse async) { async.setTimeout(2000, TimeUnit.MILLISECONDS); // Optionally, send request to executor queue for processing // ... } ... }
请注意,您可以使用 java.util.concurrent.TimeUnit
类中的任何单元来指定超时值。前面的示例没有显示将请求发送到 executor 线程池的代码。如果您只想测试超时行为,可以在资源方法正文中包含对 async.SetTimeout
的调用,每次调用时会触发超时。
AsyncResponse.NO_TIMEOUT
值代表无限超时。
默认超时
默认情况下,如果触发调用超时,JAX-RS 运行时会引发 ServiceUnavailableException
异常,并发送 HTTP 错误响应,其状态为 503
。
TimeoutHandler 接口
如果要自定义超时行为,您必须通过实施 TimeoutHandler
接口来定义超时处理程序:
// Java package javax.ws.rs.container; public interface TimeoutHandler { public void handleTimeout(AsyncResponse asyncResponse); }
当您覆盖实现类中的 handleTimeout
方法时,您可以选择以下方法来处理超时:
-
通过调用
asyncResponse.cancel
方法取消响应。 -
通过用响应值调用
asyncResponse.resume
方法来发送响应。 -
通过调用
asyncResponse.setTimeout
方法来扩展等待的时间。(例如,要等待 10 秒,您可以调用asyncResponse.setTimeout (10, TimeUnit.SECONDS)
)。
使用处理程序设置超时示例
要使用超时处理程序定义调用超时,请在 AsyncResponse
对象中调用 setTimeout
Handler 方法和 setTimeoutHandler
方法,如下例所示:
// Java ... import javax.ws.rs.GET; import javax.ws.rs.NotFoundException; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.container.AsyncResponse; import javax.ws.rs.container.Suspended; import javax.ws.rs.container.TimeoutHandler; @Path("/bookstore") public class BookContinuationStore { ... @GET @Path("/books/cancel") public void getBookDescriptionWithCancel(@PathParam("id") String id, @Suspended AsyncResponse async) { async.setTimeout(2000, TimeUnit.MILLISECONDS); async.setTimeoutHandler(new CancelTimeoutHandlerImpl()); // Optionally, send request to executor queue for processing // ... } ... }
在本例中注册一个 CancelTimeoutHandlerImpl
timeout 处理程序实例,以处理调用超时。
使用超时处理程序取消响应
CancelTimeoutHandlerImpl
timeout 处理程序定义如下:
// Java ... import javax.ws.rs.container.AsyncResponse; ... import javax.ws.rs.container.TimeoutHandler; @Path("/bookstore") public class BookContinuationStore { ... private class CancelTimeoutHandlerImpl implements TimeoutHandler { @Override public void handleTimeout(AsyncResponse asyncResponse) { asyncResponse.cancel(); } } ... }
在 AsyncResponse
对象上调用 取消
的效果是为客户端发送 HTTP 503 (服务不可用
)错误响应。您可以选择为 cancel
方法指定参数( int
或 java.util.Date
值),该值将用于在响应消息中设置 Retry-After:
HTTP 标头。但是,客户端通常忽略 Retry-After:
标头。
在可运行的实例中处理取消响应
如果您将暂停请求封装为可运行的实例,它会在 executor 线程池中排队处理,您可能会发现线程池围绕处理请求时已取消 AsyncResponse
已取消。因此,您很难将一些代码添加到可运行的实例,使它能处理已取消的
AsyncResponse
对象。例如:
// Java ... @Path("/bookstore") public class BookContinuationStore { ... private void sendRequestToThreadPool(final String id, final AsyncResponse response) { executor.execute(new Runnable() { public void run() { if ( !response.isCancelled() ) { // Process the suspended request ... // ... } } }); } ... }