我正在使用 Quarkus 3.8.6.redhat-00005 开发 Java 应用程序。在我的一门课程中,我尝试在过滤请求时从 ContainerRequestContext 的 InputStream 中读取数据。这是代码:
package br.com.bb.t99.rest;
import io.smallrye.common.annotation.Blocking;
import io.vertx.core.Future;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.http.HttpServerRequest;
import jakarta.ws.rs.container.ContainerRequestContext;
import jakarta.ws.rs.container.ContainerRequestFilter;
import jakarta.ws.rs.container.PreMatching;
import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.ext.Provider;
import java.io.IOException;
@Provider
@PreMatching
public class TesteFilter implements ContainerRequestFilter {
@Context
HttpServerRequest request;
@Override
public void filter(ContainerRequestContext containerRequestContext) throws IOException {
containerRequestContext.getEntityStream().readAllBytes();
//TODO: Edit the request body
}
}
当我尝试运行此程序时,我收到 BlockingNotAllowedException 并显示消息尝试在 io 线程上进行阻塞读取。完整的错误消息是:
org.jboss.resteasy.reactive.common.core.BlockingNotAllowedException:尝试在 io 线程上进行阻塞读取
19:34:45 ERROR [br.co.bb.de.er.re.fi.ExceptionFilter] (vert.x-eventloop-thread-1) Resp {statusCode=500, body={errors=[{code=ERRO_SISTEMA, message=Erro na execu??o da solicita??o., variaveisMonitoradas={ORIGEM-ERRO=br.com.bb.t99.rest.TesteFilter - linha: 25., MOTIVO-ERRO=org.jboss.resteasy.reactive.common.core.BlockingNotAllowedException: Attempting a blocking read on io thread, ID-REQUISICAO=347f2608-7f8e-447a-8b35-39d08c8a32f5}}]}}: org.jboss.resteasy.reactive.common.core.BlockingNotAllowedException: Attempting a blocking read on io thread
at org.jboss.resteasy.reactive.server.vertx.VertxInputStream$VertxBlockingInput.readBlocking(VertxInputStream.java:245)
at org.jboss.resteasy.reactive.server.vertx.VertxInputStream.readIntoBuffer(VertxInputStream.java:123)
at org.jboss.resteasy.reactive.server.vertx.VertxInputStream.read(VertxInputStream.java:85)
at java.base/java.io.InputStream.readNBytes(InputStream.java:412)
at java.base/java.io.InputStream.readAllBytes(InputStream.java:349)
at br.com.bb.t99.rest.TesteFilter.filter(TesteFilter.java:25)
at org.jboss.resteasy.reactive.server.handlers.ResourceRequestFilterHandler.handle(ResourceRequestFilterHandler.java:48)
at io.quarkus.resteasy.reactive.server.runtime.QuarkusResteasyReactiveRequestContext.invokeHandler(QuarkusResteasyReactiveRequestContext.java:131)
at org.jboss.resteasy.reactive.common.core.AbstractResteasyReactiveContext.run(AbstractResteasyReactiveContext.java:147)
at org.jboss.resteasy.reactive.server.handlers.RestInitialHandler.beginProcessing(RestInitialHandler.java:48)
at org.jboss.resteasy.reactive.server.vertx.ResteasyReactiveVertxHandler.handle(ResteasyReactiveVertxHandler.java:23)
at org.jboss.resteasy.reactive.server.vertx.ResteasyReactiveVertxHandler.handle(ResteasyReactiveVertxHandler.java:10)
at io.vertx.ext.web.impl.RouteState.handleContext(RouteState.java:1285)
at io.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:177)
at io.vertx.ext.web.impl.RoutingContextImpl.next(RoutingContextImpl.java:137)
at io.quarkus.vertx.http.runtime.options.HttpServerCommonHandlers$1.handle(HttpServerCommonHandlers.java:62)
at io.quarkus.vertx.http.runtime.options.HttpServerCommonHandlers$1.handle(HttpServerCommonHandlers.java:40)
at io.vertx.ext.web.impl.RouteState.handleContext(RouteState.java:1285)
at io.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:177)
at io.vertx.ext.web.impl.RoutingContextImpl.next(RoutingContextImpl.java:137)
at io.quarkus.resteasy.reactive.server.runtime.ResteasyReactiveRecorder$13.handle(ResteasyReactiveRecorder.java:339)
at io.quarkus.resteasy.reactive.server.runtime.ResteasyReactiveRecorder$13.handle(ResteasyReactiveRecorder.java:332)
at io.vertx.ext.web.impl.RouteState.handleContext(RouteState.java:1285)
at io.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:177)
at io.vertx.ext.web.impl.RoutingContextImpl.next(RoutingContextImpl.java:137)
at io.quarkus.vertx.http.runtime.devmode.VertxHttpHotReplacementSetup.handleHotReplacementRequest(VertxHttpHotReplacementSetup.java:133)
at io.quarkus.vertx.http.runtime.VertxHttpRecorder$5.handle(VertxHttpRecorder.java:415)
at io.quarkus.vertx.http.runtime.VertxHttpRecorder$5.handle(VertxHttpRecorder.java:411)
at io.vertx.ext.web.impl.RouteState.handleContext(RouteState.java:1285)
at io.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:177)
at io.vertx.ext.web.impl.RoutingContextImpl.next(RoutingContextImpl.java:137)
at io.vertx.ext.web.impl.RouterImpl.handle(RouterImpl.java:68)
at io.vertx.ext.web.impl.RouterImpl.handle(RouterImpl.java:37)
at io.quarkus.vertx.http.runtime.options.HttpServerCommonHandlers$2.handle(HttpServerCommonHandlers.java:86)
at io.quarkus.vertx.http.runtime.options.HttpServerCommonHandlers$2.handle(HttpServerCommonHandlers.java:69)
at io.quarkus.vertx.http.runtime.VertxHttpRecorder$1.handle(VertxHttpRecorder.java:147)
at io.quarkus.vertx.http.runtime.VertxHttpRecorder$1.handle(VertxHttpRecorder.java:123)
at io.quarkus.vertx.http.runtime.devmode.VertxHttpHotReplacementSetup$4.handle(VertxHttpHotReplacementSetup.java:190)
at io.quarkus.vertx.http.runtime.devmode.VertxHttpHotReplacementSetup$4.handle(VertxHttpHotReplacementSetup.java:181)
at io.vertx.core.impl.future.FutureImpl$4.onSuccess(FutureImpl.java:176)
at io.vertx.core.impl.future.FutureBase.lambda$emitSuccess$0(FutureBase.java:60)
at io.netty.util.concurrent.AbstractEventExecutor.runTask(AbstractEventExecutor.java:173)
at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:166)
at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:470)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:569)
at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:997)
at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.base/java.lang.Thread.run(Thread.java:1583)
19:34:45 ERROR [or.jb.re.re.se.co.RuntimeExceptionMapper] (vert.x-eventloop-thread-1) A blocking operation occurred on the IO thread. This likely means you need to use the @io.smallrye.common.annotation.Blocking annotation on the Resource method, class or jakarta.ws.rs.core.Application class.
--
2 tests failed (11 passing, 0 skipped), 2 tests were run in 1737078ms. Tests completed at 19:34:18 due to changes to TesteFilter.class.
Press [e] to edit command line args (currently ''), [r] to re-run, [o] Toggle test output, [:] for the terminal, [h] for more options>
我不完全明白为什么会发生这种情况。在 Quarkus 中是否有一种以非阻塞方式读取和编辑请求正文的首选方法?如何解决这个问题?任何指导将不胜感激。
我已经尝试将 @io.smallrye.common.annotation.Blocking 注释添加到端点、扩展 jakarta.ws.rs.core.Application 的类以及过滤器本身。然而,所有这些尝试都未能成功解决问题。
您使用的方法会导致此错误,因为在使用 @PreMatching 过滤器时,预计操作是非阻塞的,因为 事件循环始终用于这些操作。 在ContainerRequestContext中读取InputStream的操作是阻塞的,由于它是在事件循环中执行的,所以会抛出org.jboss.resteasy.reactive.common.core.BlockingNotAllowedException。
考虑到抛出的异常以及您在之前的评论中提到的过滤器的目的,我相信该问题的可能解决方案如下:
package com.example;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.logging.Logger;
import org.jboss.resteasy.reactive.server.ServerRequestFilter;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.vertx.core.http.HttpServerRequest;
import jakarta.ws.rs.container.ContainerRequestContext;
import jakarta.ws.rs.container.PreMatching;
import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.ext.Provider;
@Provider
public class TesteFilter {
private static final Logger LOGGER = Logger.getLogger(TesteFilter.class.getName());
@Context
HttpServerRequest request;
@ServerRequestFilter
public void doFilter(ContainerRequestContext containerRequestContext) throws IOException {
LOGGER.info("Intercepting the request in the Filter");
String body = new String(containerRequestContext.getEntityStream().readAllBytes());
LOGGER.info("Original request body: " + body);
ObjectMapper mapper = new ObjectMapper();
Language language = mapper.readValue(body, Language.class);
String modifiedBody = mapper.writeValueAsString(
new Language("Modified-" + language.getType(),
"Modified-" + language.getName()
));
LOGGER.info("Modified request body: " + modifiedBody);
containerRequestContext.setEntityStream(new ByteArrayInputStream(modifiedBody.getBytes()));
}
}
以下是涵盖该主题的 Quarkus 文档: 请求或响应过滤器 - Quarkus 文档
最后但同样重要的是,您提到您正在使用 Quarkus 版本 3.8.6.redhat-00005,这让我相信您已经订阅了 Quarkus 的 Red Hat Build。 不要犹豫,向红帽开具支持票,以获得有关此类问题的帮助。