这是一个关于 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 1
```
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))。给后面搜索的人做提醒。 |