这是一个关于 vertx web server 的简单 demo. 我设置了两个 handler, 一个用于打印一行文字, 另一个用来做一个反向代理,将请求转发到 baidu.com.
第一个代码块是一个正确的写法,但我在这个需求上,想要把第二个 handler 用代理的形式放到第一个 handler 里面,即合二为一. 这个处理我写在第二个代码块里, 但我有一些疑问, 请您帮我解答一下疑惑?
我有三个问题, 并且将这些问题放在了代码注释里,以 Issue 开头标注.
原始代码块
public class VertxRouteDemo { public static void main(String[] args) { Vertx vertx = Vertx.vertx(); HttpServer server = vertx.createHttpServer(); Router router = Router.router(vertx); router.route() // 第一个 handler .handler(event -> { System.out.println("Just print to confirm executed"); event.next(); }); HttpClient httpClient = vertx.createHttpClient(); HttpProxy proxy = HttpProxy.reverseProxy( httpClient).origin(80, "baidu.com"); // 第二个 handler router.route().handler(proxy); server.requestHandler(router); server.listen(18081); } }
修改后的代码块
public class VertxRouteDemo { public static void main(String[] args) { Vertx vertx = Vertx.vertx(); HttpServer server = vertx.createHttpServer(); Router router = Router.router(vertx); router.route() .handler(event -> { System.out.println("Just print to confirm executed"); // 把它挪到这里,相当于对第二个 handler 做了代理,打印一行信息确认是否执行 HttpClient httpClient = vertx.createHttpClient(); HttpProxy proxy = HttpProxy.reverseProxy( httpClient).origin(80, "baidu.com"); // Issue 1: 这里是否会导致阻塞? // 我猜测大概是不会导致阻塞的,即非阻塞,就是说这个方法立即返回。 // 在非阻塞的前提下引出第二个问题,我希望这个方法执行完成后再去调用下面的 next(),这段代码逻辑是不是有问题? // 因为这个方法立即返回,那就会立即去执行下面的 next()方法了 // Issue 2: 如果这里是非阻塞方法,那我应该怎么改才能达到目的 proxy.handle(event); event.next(); }); server.requestHandler(router); server.listen(18081); } }
第二个修改后的代码块
public class VertxRouteDemo { public static void main(String[] args) { Vertx vertx = Vertx.vertx(); HttpServer server = vertx.createHttpServer(); Router router = Router.router(vertx); router.route() .handler(event -> { System.out.println("Just print to confirm executed"); // 把它挪到这里,相当于对第二个 handler 做了代理,打印一行信息确认是否执行 HttpClient httpClient = vertx.createHttpClient(); HttpProxy proxy = HttpProxy.reverseProxy( httpClient).origin(80, "baidu.com"); // 假设 handle(event)是阻塞的,所以使用了这种方法去使它不阻塞 eventloop 线程 // Issue 3: 这是写是对的吗? vertx.executeBlocking(promise -> { proxyHandler.handle(event); promise.complete(); }, result -> { if (result.succeeded()) { // 阻塞操作完成后异步调用 event.next() event.next(); } else { // 处理阻塞操作失败的情况 event.fail(result.cause()); } }); event.next(); }); server.requestHandler(router); server.listen(18081); } }
1 v2defe OP <details> <summary>以下是 chatGPT3.5 的回复, 关于 Issue2, 它给出了一个不存在的方法来解决</summary> 首先,让我回答你的三个问题: Issue 1: 这里是否会导致阻塞? 答:不会导致阻塞。在 Vert.x 中,大部分操作都是非阻塞的,包括创建 HttpClient 和配置反向代理。这些方法会立即返回,不会阻塞事件循环线程。 Issue 2: 如果这里是非阻塞方法,那我应该怎么改才能达到目的? 答:在这种情况下,你可以使用异步回调来实现在代理处理完成后再调用 event.next()。可以通过 proxy.handle()方法的回调函数来处理这个逻辑,而不是在调用 proxy.handle()之后立即调用 event.next()。这样,event.next()将在代理处理完成后被调用。 ```java router.route().handler(event -> { System.out.println("Just print to confirm executed"); HttpClient httpClient = vertx.createHttpClient(); HttpProxy proxy = HttpProxy.reverseProxy( httpClient).origin(80, "baidu.com"); proxy.handle(event, proxyResult -> { // 在代理处理完成后调用 event.next() event.next(); }); }); ``` Issue 3: 这是写是对的吗? 答:这个代码块中使用了 vertx.executeBlocking 方法来将阻塞操作封装为异步操作。这种方法在某些情况下是有效的,但要注意的是,如果你的目标是将阻塞操作转换为非阻塞操作,那么在 executeBlocking 中执行阻塞操作的目的就没有实现。 在你的代码中,如果 proxy.handle()方法是非阻塞的,那么使用 vertx.executeBlocking 没有必要。如果 proxy.handle()方法是阻塞的,那么你的代码是正确的,因为它将阻塞操作封装在一个异步操作中,并在操作完成后调用 event.next()。只要确保阻塞操作在异步操作中得到正确处理即可。 希望以上解答能帮助你理解和解决问题。如果还有其他疑问,请随时提出。 </details> |
2 v2defe OP 请问有办法处理第二个题吗? gpt 的回复是错误的 |
![]() | 3 ovoo 2023-06-30 19:40:12 +08:00 ![]() ``` public void start(Promise<Void> startPromise) throws Exception { HttpServer server = vertx.createHttpServer(); Router router = Router.router(vertx); router.route() .handler(event -> { System.out.println(1); HttpClient httpClient = vertx.createHttpClient(); HttpProxy proxy = HttpProxy.reverseProxy( httpClient).origin(80, "baidu.com"); proxy.handle(event.request()); event.addEndHandler(h -> event.next()); }); router.route().handler(e -> System.out.println(3)); server.requestHandler(router).exceptionHandler(throwable -> System.out.println(throwable.getMessage())); server.listen(18081); } ``` 以上代码可以实现代理,并按 route 添加顺序打印出 1 , 3 |
5 v2defe OP @ovoo 老哥厉害,是可用的。看起来跟 gpt 给出的思路大致是一致的,需要通过 vertx 支持的方式去插入定制的处理器,来实现异步回调。 后来我发现似乎在使用了反向代理处理器的情况下,不应该再去调用 next()传递到下个处理器了。因为反向代理处理器会异步执行请求并写入响应并结束响应,如果传递到下个处理器有可能会同时对响应进行操作,从而发生冲突。 但是还是很感谢提供了处理的思路。 另外第一段我的代码写错了,纠正一下应该是 router.route().handler(ProxyHandler.create(proxy))。给后面搜索的人做提醒。 |