Quarkus中GET请求触发BlockingNotAllowedException问题咨询
我定义了一个读取请求体并映射为Java POJO的REST端点,当发送GET请求时会抛出org.jboss.resteasy.reactive.common.core.BlockingNotAllowedException异常,但将请求类型改为POST后可正常执行。
代码示例:
@Path("/test") @GET @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) public Uni<List<String>> getData(RequestBody requestBody) { // 业务代码 }
我推测是Jackson库在将请求体映射为POJO时导致该异常,但疑惑为何仅GET请求会触发此问题,恳请提供排查方向。
堆栈信息:
{ "details": "Error id c307388f-26ed-4108-bb1c-12032de09243-1, org.jboss.resteasy.reactive.common.core.BlockingNotAllowedException: Attempting a blocking read on io thread", "stack": "org.jboss.resteasy.reactive.common.core.BlockingNotAllowedException: Attempting a blocking read on io thread\r\n\tat org.jboss.resteasy.reactive.server.vertx.VertxInputStream$VertxBlockingInput.readBlocking(VertxInputStream.java:242)\r\n\tat org.jboss.resteasy.reactive.server.vertx.VertxInputStream.readIntoBuffer(VertxInputStream.java:120)\r\n\tat org.jboss.resteasy.reactive.server.vertx.VertxInputStream.read(VertxInputStream.java:82)\r\n\tat com.fasterxml.jackson.core.json.ByteSourceJsonBootstrapper.ensureLoaded(ByteSourceJsonBootstrapper.java:539)\r\n\tat com.fasterxml.jackson.core.json.ByteSourceJsonBootstrapper.detectEncoding(ByteSourceJsonBootstrapper.java:133)\r\n\tat com.fasterxml.jackson.core.json.ByteSourceJsonBootstrapper.constructParser(ByteSourceJsonBootstrapper.java:256)\r\n\tat com.fasterxml.jackson.core.JsonFactory._createParser(JsonFactory.java:1655)\r\n\tat com.fasterxml.jackson.core.JsonFactory.createParser(JsonFactory.java:1083)\r\n\tat com.fasterxml.jackson.databind.ObjectReader.createParser(ObjectReader.java:1049)\r\n\tat com.fasterxml.jackson.databind.ObjectReader.readValue(ObjectReader.java:1427)\r\n\tat io.quarkus.resteasy.reactive.jackson.runtime.serialisers.ServerJacksonMessageBodyReader.doReadFrom(ServerJacksonMessageBodyReader.java:62)\r\n\tat io.quarkus.resteasy.reactive.jackson.runtime.serialisers.ServerJacksonMessageBodyReader.readFrom(ServerJacksonMessageBodyReader.java:53)\r\n\tat org.jboss.resteasy.reactive.server.handlers.RequestDeserializeHandler.readFrom(RequestDeserializeHandler.java:108)\r\n\tat org.jboss.resteasy.reactive.server.handlers.RequestDeserializeHandler.handle(RequestDeserializeHandler.java:68)\r\n\tat org.jboss.resteasy.reactive.server.handlers.RequestDeserializeHandler.handle(RequestDeserializeHandler.java:25)\r\n\tat org.jboss.resteasy.reactive.common.core.AbstractResteasyReactiveContext.run(AbstractResteasyReactiveContext.java:141)\r\n\tat org.jboss.resteasy.reactive.server.handlers.RestInitialHandler.beginProcessing(RestInitialHandler.java:49)\r\n\tat org.jboss.resteasy.reactive.server.vertx.ResteasyReactiveVertxHandler.handle(ResteasyReactiveVertxHandler.java:17)\r\n\tat org.jboss.resteasy.reactive.server.vertx.ResteasyReactiveVertxHandler.handle(ResteasyReactiveVertxHandler.java:7)\r\n\tat io.vertx.ext.web.impl.RouteState.handleContext(RouteState.java:1212)\r\n\tat io.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:163)\r\n\tat io.vertx.ext.web.impl.RoutingContextImpl.next(RoutingContextImpl.java:141)\r\n\tat io.quarkus.vertx.http.runtime.StaticResourcesRecorder$2.handle(StaticResourcesRecorder.java:83)\r\n\tat io.quarkus.vertx.http.runtime.StaticResourcesRecorder$2.handle(StaticResourcesRecorder.java:67)\r\n\tat io.vertx.ext.web.impl.RouteState.handleContext(RouteState.java:1212)\r\n\tat io.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:126)\r\n\tat io.vertx.ext.web.impl.RoutingContextImpl.next(RoutingContextImpl.java:141)\r\n\tat io.vertx.ext.web.handler.impl.StaticHandlerImpl.lambda$sendStatic$1(StaticHandlerImpl.java:274)\r\n\tat io.vertx.core.impl.future.FutureImpl$3.onSuccess(FutureImpl.java:141)\r\n\tat io.vertx.core.impl.future.FutureBase.lambda$emitSuccess$0(FutureBase.java:54)\r\n\tat io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:164)\r\n\tat io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:469)\r\n\tat io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:503)\r\n\tat io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:986)\r\n\tat io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)\r\n\tat io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)\r\n\tat java.base/java.lang.Thread.run(Thread.java:834)" }
排查方向
HTTP规范与框架处理逻辑差异:HTTP规范里GET请求本就不应该携带请求体,虽然部分客户端能发送,但Resteasy Reactive对GET和POST的请求体处理逻辑完全不同。POST是标准带请求体的方法,框架会自动把请求体读取调度到工作线程,适配非阻塞流程;但GET请求的请求体读取被框架当成非常规操作,直接在IO线程执行阻塞读取,而Jackson解析是阻塞式的,自然触发
BlockingNotAllowedException。框架请求体调度策略:Resteasy Reactive针对POST这类标准方法,会将请求体读取、JSON解析等操作放到工作线程池,避免阻塞IO线程;但GET请求默认没有这个调度逻辑,导致Jackson在IO线程做阻塞读取,触发异常。
端点注解的合理性:你的端点同时使用
@GET和@Consumes(MediaType.APPLICATION_JSON),这不符合常规HTTP用法。先确认业务是否真的需要用GET传递JSON请求体,如果必须这么做,得显式配置框架允许,并把阻塞操作转移到工作线程。Quarkus配置调整:可以尝试添加配置
quarkus.resteasy-reactive.allow-get-method-with-body=true开启GET请求读取请求体的支持,同时给方法添加@Blocking注解,让框架把整个方法的执行转移到工作线程池,避免IO线程阻塞。
内容的提问来源于stack exchange,提问作者Jaiprasad

