You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vert.x 3多HTTP服务器部署及无URL跳转表单请求技术问询

Vert.x 3 跨端口请求与多Verticle部署问题解答

Hey there! Let's tackle your questions step by step—they're all super common when building distributed Vert.x apps, so I've got you covered.

1. 不改变地址栏实现跨端口表单请求(可行,用Ajax+Vert.x CORS配置)

Absolutely, you can do this! The key is to prevent the default form submission behavior (which causes a page reload/URL change) and use Ajax to send requests behind the scenes. Since you're hitting different ports (9090, 9091 from 8080), you'll also need to configure CORS on your backend Verticles to allow cross-origin requests.

示例代码

前端页面(localhost:8080/home 返回的HTML)

<!DOCTYPE html>
<html>
<head>
    <title>Home Page</title>
</head>
<body>
    <!-- 第一个表单:请求9090/list -->
    <form id="listForm">
        <input type="text" name="list"/>
        <input type="submit" value="Submit List"/>
    </form>

    <!-- 第二个表单:请求9091/insert -->
    <form id="insertForm">
        <input type="text" name="insert"/>
        <input type="submit" value="Submit Insert"/>
    </form>

    <script>
        // 拦截第一个表单提交
        document.getElementById('listForm').addEventListener('submit', async (e) => {
            e.preventDefault(); // 阻止默认跳转
            const formData = new FormData(e.target);
            try {
                const response = await fetch('http://localhost:9090/list', {
                    method: 'POST',
                    body: formData
                });
                const result = await response.text();
                console.log('List request result:', result);
                // 这里可以更新页面内容,比如显示成功/失败信息
            } catch (error) {
                console.error('List request failed:', error);
            }
        });

        // 拦截第二个表单提交
        document.getElementById('insertForm').addEventListener('submit', async (e) => {
            e.preventDefault();
            const formData = new FormData(e.target);
            try {
                const response = await fetch('http://localhost:9091/insert', {
                    method: 'POST',
                    body: formData
                });
                const result = await response.text();
                console.log('Insert request result:', result);
            } catch (error) {
                console.error('Insert request failed:', error);
            }
        });
    </script>
</body>
</html>

主Verticle(监听8080,负责/home页面)

import io.vertx.core.AbstractVerticle;
import io.vertx.core.http.HttpServer;
import io.vertx.ext.web.Router;

public class MainVerticle extends AbstractVerticle {
    @Override
    public void start() {
        Router router = Router.router(vertx);
        
        // 处理/home请求,返回上面的HTML页面
        router.get("/home").handler(ctx -> {
            ctx.response()
               .putHeader("Content-Type", "text/html")
               .sendFile("path/to/your/home.html"); // 替换为你的HTML文件路径
        });

        HttpServer server = vertx.createHttpServer();
        server.requestHandler(router).listen(8080, res -> {
            if (res.succeeded()) {
                System.out.println("Main server running on port 8080");
            } else {
                System.err.println("Failed to start main server: " + res.cause());
            }
        });
    }
}

ListVerticle(监听9090,处理/list请求,带CORS配置)

import io.vertx.core.AbstractVerticle;
import io.vertx.core.http.HttpServer;
import io.vertx.ext.web.Router;
import io.vertx.ext.web.handler.CorsHandler;

import java.util.HashSet;
import java.util.Set;

public class ListVerticle extends AbstractVerticle {
    @Override
    public void start() {
        Router router = Router.router(vertx);
        
        // 配置CORS,允许来自8080的请求
        Set<String> allowedOrigins = new HashSet<>();
        allowedOrigins.add("http://localhost:8080");
        router.route().handler(CorsHandler.create(allowedOrigins)
               .allowedMethod(io.vertx.core.http.HttpMethod.POST)
               .allowedHeader("Content-Type"));

        // 处理/list POST请求
        router.post("/list").handler(ctx -> {
            String listParam = ctx.request().getParam("list");
            ctx.response()
               .putHeader("Content-Type", "text/plain")
               .end("Received list parameter: " + listParam);
        });

        HttpServer server = vertx.createHttpServer();
        server.requestHandler(router).listen(9090, res -> {
            if (res.succeeded()) {
                System.out.println("List server running on port 9090");
            } else {
                System.err.println("Failed to start list server: " + res.cause());
            }
        });
    }
}

InsertVerticle(监听9091,处理/insert请求,带CORS配置)

import io.vertx.core.AbstractVerticle;
import io.vertx.core.http.HttpServer;
import io.vertx.ext.web.Router;
import io.vertx.ext.web.handler.CorsHandler;

import java.util.HashSet;
import java.util.Set;

public class InsertVerticle extends AbstractVerticle {
    @Override
    public void start() {
        Router router = Router.router(vertx);
        
        // 配置CORS,允许来自8080的请求
        Set<String> allowedOrigins = new HashSet<>();
        allowedOrigins.add("http://localhost:8080");
        router.route().handler(CorsHandler.create(allowedOrigins)
               .allowedMethod(io.vertx.core.http.HttpMethod.POST)
               .allowedHeader("Content-Type"));

        // 处理/insert POST请求
        router.post("/insert").handler(ctx -> {
            String insertParam = ctx.request().getParam("insert");
            ctx.response()
               .putHeader("Content-Type", "text/plain")
               .end("Received insert parameter: " + insertParam);
        });

        HttpServer server = vertx.createHttpServer();
        server.requestHandler(router).listen(9091, res -> {
            if (res.succeeded()) {
                System.out.println("Insert server running on port 9091");
            } else {
                System.err.println("Failed to start insert server: " + res.cause());
            }
        });
    }
}

部署所有Verticle的主类

import io.vertx.core.Vertx;

public class AppStarter {
    public static void main(String[] args) {
        Vertx vertx = Vertx.vertx();
        
        // 部署三个Verticle
        vertx.deployVerticle(new MainVerticle());
        vertx.deployVerticle(new ListVerticle());
        vertx.deployVerticle(new InsertVerticle());
    }
}

2. 部署多端口Verticle是否合理?当然合理,优势很多!

Deploying separate Verticles listening on different ports is a great practice in Vert.x, especially for microservices or modular apps. Here are the key advantages:

  • 职责分离: Each Verticle handles a specific business domain (e.g., list operations vs insert operations), making your codebase cleaner and easier to maintain.
  • 独立扩容: If one endpoint gets more traffic (say, /list is hit 10x more than /insert), you can deploy multiple instances of ListVerticle without touching the others.
  • 故障隔离: If one Verticle crashes (e.g., InsertVerticle has a bug), it won't take down the entire app—MainVerticle and ListVerticle will keep running.
  • 便于测试: You can test each Verticle independently (e.g., hit localhost:9090/list directly without going through the home page).
  • 灵活部署: You can deploy Verticles on different machines later if needed, just update the URLs in your frontend.

3. 解决"Resources not found"偶尔出现的问题

The intermittent 404 errors usually come from one of these issues—let's fix them:

常见原因与解决方案

  • Verticle部署顺序: Sometimes, your frontend might send requests before the target Verticle (9090/9091) finishes starting up. Add deployment handlers to ensure all Verticles are ready before serving the home page, or add retry logic in your Ajax calls.
    // 修改AppStarter,确保所有Verticle部署完成后再启动主服务
    vertx.deployVerticle(new ListVerticle(), listRes -> {
        if (listRes.succeeded()) {
            vertx.deployVerticle(new InsertVerticle(), insertRes -> {
                if (insertRes.succeeded()) {
                    vertx.deployVerticle(new MainVerticle());
                }
            });
        }
    });
    
  • 路由路径不匹配: Double-check that your Verticle's route exactly matches the request path. For example, if you have router.post("/list/") (with a trailing slash) but send to /list, it will 404. Keep paths consistent.
  • 端口绑定冲突: Ensure no other process is using ports 9090/9091. You can add logging to confirm the server is listening on the correct port (like the System.out.println lines in the example code).
  • CORS配置遗漏: If CORS is misconfigured, browsers might block the request, which can sometimes look like a 404. Verify your CorsHandler allows the correct origin, method, and headers.
  • Vert.x实例问题: If you're creating multiple Vertx instances accidentally, some Verticles might not bind properly. Always use a single Vertx instance for deploying all Verticles (like in the AppStarter example).

内容的提问来源于stack exchange,提问作者kasko

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 07:35:04