将每个请求的响应延迟添加到自定义 HttpService 的正确方法
Right way to add a per-request response delay to a custom HttpService
这是我目前对 HttpService.serve()
的实现
@Override
public HttpResponse serve(ServiceRequestContext ctx, HttpRequest req) throws Exception {
return HttpResponse.from(req.aggregate().thenApply(ahr -> {
MyResponse myResponse = Utils.handle(ahr);
HttpResponse httpResponse Utils.toResponse(myResponse);
return httpResponse;
}));
}
我有一个用户定义的响应延迟,它可以根据每个单独的请求-响应而变化,这在 myResponse
对象中可用。
以非阻塞方式应用此延迟的最佳方法是什么,我可以看到一些 delay
API-s 但它们在 HttpResponse
中受到保护。流式 API 设计或装饰器的任何额外提示或指示都会有所帮助。我真的从 Armeria 代码库中学到了很多东西:)
如果您甚至在使用请求正文之前就知道所需的延迟,您可以简单地使用 HttpResponse.delayed()
:
@Override
public HttpResponse serve(ServiceRequestContext ctx, HttpRequest req) throws Exception {
return HttpResponse.delayed(
HttpResponse.of(200),
Duration.ofSeconds(3),
ctx.eventLoop());
}
如果你需要消费内容或执行一些操作来计算所需的延迟,你可以结合HttpResponse.delayed()
和HttpResponse.from()
:
@Override
public HttpResponse serve(ServiceRequestContext ctx, HttpRequest req) throws Exception {
return HttpResponse.from(req.aggregate().thenApply(ahr -> {
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
MyResponse myResponse = Utils.handle(ahr);
HttpResponse httpResponse = Utils.toResponse(myResponse);
Duration myDelay = Utils.delayMillis(...);
return HttpResponse.delayed(httpResponse, myDelay, ctx.eventLoop());
// ^^^^^^^
});
}
如果延迟实际上不是延迟而是等待某事发生,可以使用更强大的CompletableFuture.thenCompose()
:
@Override
public HttpResponse serve(ServiceRequestContext ctx, HttpRequest req) throws Exception {
return HttpResponse.from(req.aggregate().thenCompose(ahr -> {
// ^^^^^^^^^^^
My1stResponse my1stRes = Utils.handle(ahr);
// Schedule some asynchronous task that returns another future.
CompletableFuture<My2ndResponse> myFuture = doSomething(my1stRes);
// Map the future into an HttpResponse.
return myFuture.thenApply(my2ndRes -> {
HttpResponse httpRes = Utils.toResponse(my1stRes, my2ndRes);
return httpRes;
});
});
}
对于更复杂的工作流,我建议您研究 Reactive Streams 实现,例如 Project Reactor 和 RxJava,它们提供了避免回调地狱的工具。
这是我目前对 HttpService.serve()
@Override
public HttpResponse serve(ServiceRequestContext ctx, HttpRequest req) throws Exception {
return HttpResponse.from(req.aggregate().thenApply(ahr -> {
MyResponse myResponse = Utils.handle(ahr);
HttpResponse httpResponse Utils.toResponse(myResponse);
return httpResponse;
}));
}
我有一个用户定义的响应延迟,它可以根据每个单独的请求-响应而变化,这在 myResponse
对象中可用。
以非阻塞方式应用此延迟的最佳方法是什么,我可以看到一些 delay
API-s 但它们在 HttpResponse
中受到保护。流式 API 设计或装饰器的任何额外提示或指示都会有所帮助。我真的从 Armeria 代码库中学到了很多东西:)
如果您甚至在使用请求正文之前就知道所需的延迟,您可以简单地使用 HttpResponse.delayed()
:
@Override
public HttpResponse serve(ServiceRequestContext ctx, HttpRequest req) throws Exception {
return HttpResponse.delayed(
HttpResponse.of(200),
Duration.ofSeconds(3),
ctx.eventLoop());
}
如果你需要消费内容或执行一些操作来计算所需的延迟,你可以结合HttpResponse.delayed()
和HttpResponse.from()
:
@Override
public HttpResponse serve(ServiceRequestContext ctx, HttpRequest req) throws Exception {
return HttpResponse.from(req.aggregate().thenApply(ahr -> {
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
MyResponse myResponse = Utils.handle(ahr);
HttpResponse httpResponse = Utils.toResponse(myResponse);
Duration myDelay = Utils.delayMillis(...);
return HttpResponse.delayed(httpResponse, myDelay, ctx.eventLoop());
// ^^^^^^^
});
}
如果延迟实际上不是延迟而是等待某事发生,可以使用更强大的CompletableFuture.thenCompose()
:
@Override
public HttpResponse serve(ServiceRequestContext ctx, HttpRequest req) throws Exception {
return HttpResponse.from(req.aggregate().thenCompose(ahr -> {
// ^^^^^^^^^^^
My1stResponse my1stRes = Utils.handle(ahr);
// Schedule some asynchronous task that returns another future.
CompletableFuture<My2ndResponse> myFuture = doSomething(my1stRes);
// Map the future into an HttpResponse.
return myFuture.thenApply(my2ndRes -> {
HttpResponse httpRes = Utils.toResponse(my1stRes, my2ndRes);
return httpRes;
});
});
}
对于更复杂的工作流,我建议您研究 Reactive Streams 实现,例如 Project Reactor 和 RxJava,它们提供了避免回调地狱的工具。