我正在设置一个api网关。我想在请求BE服务之前验证授权令牌。我收到了IllegalStateException:请求已被读取。请帮忙。
我将测试项目代码上传到GitHub。 https://github.com/EddyPan/test-demo
(apply #'funcall #'mapcar #'list '((a b) (c d) (e f)))
例外:
router.route().path("/user/admin").method(HttpMethod.POST)
.handler(rct -> {
HttpServerRequest request = rct.request().setExpectMultipart(true);
MultiMap headers = request.headers();
JsonObject param = new JsonObject().put("requestUrl", "http://localhost:18080/authorize")
.put("httpMethod", "POST");
webClient.postAbs("http://localhost:18080/authorize")
.timeout(6000)
.putHeader("Content-Type", "application/json")
.putHeader("Authorization", headers.get("Authorization"))
.as(BodyCodec.jsonObject())
.sendJsonObject(param, ar -> authHandler(rct, ar));
});
答案 0 :(得分:0)
我解决了这个问题。在调用auth api之前,我先暂停原始请求,并在授权完成后恢复缓冲区处理。
router.route().path("/user/admin").method(HttpMethod.POST)
.handler(rct -> {
HttpServerRequest request = rct.request().setExpectMultipart(true);
request.pause(); // Here is to pasue the origin request.
MultiMap headers = request.headers();
JsonObject param = new JsonObject().put("requestUrl", "http://localhost:18080/authorize")
.put("httpMethod", "POST");
webClient.postAbs("http://localhost:18080/authorize")
.timeout(6000)
.putHeader("Content-Type", "application/json")
.putHeader("Authorization", headers.get("Authorization"))
.as(BodyCodec.jsonObject())
.sendJsonObject(param, ar -> authHandler(rct, ar));
});
答案 1 :(得分:0)
导致此错误的两个原因:
Handler
之前异步 BodyHandler
如 BodyHandler
的 Vert.X documentation 所述:
使用此处理程序要求它尽快安装在路由器中,因为它需要安装处理程序来使用 HTTP 请求正文,并且必须在执行任何请求之前完成此操作异步调用。
router.post(endpoint)
.consumes(contentType)
.handler(bodyHandler) <<<<<<<<< first this
.handler(authHandler) <<<<<<<< then this async handler;
参见 Vert.X documentation:
<块引用>如果之前需要异步调用,则应暂停然后恢复 HttpServerRequest,以便在主体处理程序准备好处理它们之前不会传递请求事件.
router.post(endpoint)
.consumes(contentType)
.handler(authHandler)
.handler(bodyHandler);
BodyHandler implements Handler<RoutingContext> {
@Override
public void handle(final RoutingContext ctx) {
// pause request delivery
ctx.request().pause();
asyncCall(r -> {
// e.g. check authorization or database here
// resume request delivery
ctx.request.resume();
// call the next handler
ctx.next();
}
}
}
request.body()
调用假设您使用 Vert.X BodyHandler
并在其后安装了自定义处理程序:
router.post(endpoint)
.consumes(contentType)
.handler(BodyHandler.create())
.handler(customHandler);
您的自定义处理程序不得调用 request.body()
! 否则您会得到
403: body has already been read
ctx.getBody()
使用 ctx.getBody[/asJson/asString]()
获取已被 BodyHandler
读取的正文:
CustomHandler implements Handler<RoutingContext> {
@Override
public void handleAuthorizedRequest(RoutingContext ctx) {
final var body = ctx.getBodyAsJson();
// instead of: ctx.request().body();
...
}
}