Quarkus反向代理POST/PUT请求报错:Request has already been read
问题:Quarkus反向代理PUT/POST请求抛出"Request has already been read"异常
基于Quarkus搭建了一个反向代理,用于转发所有HTTP请求到另一API。GET请求可以正常工作,但PUT/POST请求失败,抛出如下异常:
java.lang.IllegalStateException: Request has already been read
实现代码如下:
处理请求的代码:
@Route(path = "/api/*") public void handleProxyRequest(RoutingContext rc) { HttpServerRequest request = rc.request(); this.httpProxy = customHttpProxy.getHttpProxy(); this.httpProxy.handle(request); }
CustomHttpProxy类代码:
@ApplicationScoped public class CustomHttpProxy { private static final Logger LOGGER = LoggerFactory.getLogger(CustomHttpProxy.class); @ConfigProperty(name = "api.originport", defaultValue = "8080") private Integer TARGET_PORT; @ConfigProperty(name = "api.originhost", defaultValue = "localhost") private String TARGET_HOST; @Inject private Vertx vertx; public HttpProxy getHttpProxy() { HttpClient proxyClient = vertx.createHttpClient(); HttpProxy proxy = HttpProxy.reverseProxy(proxyClient); proxy.origin(TARGET_PORT, TARGET_HOST); return proxy; } }
解决方案
问题根源
- 频繁创建HttpClient和HttpProxy实例:每次请求都新建客户端和代理对象,既浪费资源,还会导致请求体处理的上下文冲突;
- 请求体被提前读取:直接提取
HttpServerRequest并交给代理处理时,Quarkus/Vert.x可能已经提前读取了请求体,导致代理处理时提示请求已被读取。
修改步骤
1. 复用HttpClient和HttpProxy实例
修改CustomHttpProxy类,在初始化时创建一次客户端和代理,避免重复创建:
@ApplicationScoped public class CustomHttpProxy { private static final Logger LOGGER = LoggerFactory.getLogger(CustomHttpProxy.class); @ConfigProperty(name = "api.originport", defaultValue = "8080") private Integer TARGET_PORT; @ConfigProperty(name = "api.originhost", defaultValue = "localhost") private String TARGET_HOST; @Inject private Vertx vertx; private HttpProxy proxy; @PostConstruct void init() { HttpClient proxyClient = vertx.createHttpClient(); proxy = HttpProxy.reverseProxy(proxyClient); proxy.origin(TARGET_PORT, TARGET_HOST); } public HttpProxy getHttpProxy() { return proxy; } }
2. 让代理直接处理RoutingContext
修改请求处理方法,直接将RoutingContext交给代理处理,而不是单独提取HttpServerRequest,这样能保证请求体的正确流转:
@Route(path = "/api/*") public void handleProxyRequest(RoutingContext rc) { HttpProxy httpProxy = customHttpProxy.getHttpProxy(); httpProxy.handle(rc); }
验证说明
- 复用
HttpClient是Vert.x的官方最佳实践,能避免连接资源的不必要消耗; - 使用
handle(rc)方法可以让代理完整接管请求的所有流程,包括请求体的读取和转发,从根本上解决"请求已被读取"的异常。
内容的提问来源于stack exchange,提问作者Laazo
相关产品推荐
相关产品推荐

