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

Vert.x出现CorruptedWebSocketFrameException异常的排查与解决

问题分析与修复:Vert.x SockJS Bridge 抛出 CorruptedWebSocketFrameException

问题场景

使用Vert.x 4.4.2搭建服务时,客户端无法向服务器发送任何事件,无论请求格式或负载如何,服务端都会抛出如下异常:

10:20:36.219 [vert.x-eventloop-thread-2] ERROR io.vertx.ext.web.handler.sockjs.impl.EventBusBridgeImpl - SockJSSocket exception
io.netty.handler.codec.http.websocketx.CorruptedWebSocketFrameException: received a frame that is not masked as expected

服务端代码

public class Strange extends AbstractVerticle {

    private HttpServer server;

    @Override
    public void start() throws Exception {
        server = this.getVertx().createHttpServer();
        final Router router = Router.router(this.getVertx());
        router.route().handler(BodyHandler.create());
        router.route().handler(StaticHandler.create());
        // SOCKS
        final SockJSBridgeOptions opts = new SockJSBridgeOptions()
                .addInboundPermitted(new PermittedOptions().setAddressRegex(".*"))
                .addOutboundPermitted(new PermittedOptions().setAddressRegex(".*"));
        final SockJSHandler sockJSHandler = SockJSHandler.create(this.getVertx());
        final var socks = sockJSHandler.bridge(opts, event -> {
            if (event.type() == BridgeEventType.SOCKET_CREATED) {
                log.atInfo().log("Socket was created ...");
            }
            event.complete(true);
        });

        router.route("/*")
                .handler(StaticHandler.create(StaticHandler.DEFAULT_WEB_ROOT))
                .subRouter(socks);
        server.requestHandler(router);
        server.listen(80);
    }

    @Override
    public void stop() throws Exception {
        this.server.close();
    }
}

客户端代码

<!DOCTYPE html>
<html lang="de">
<head>
    <script src="lib/vertx/sockjs.min.js" type="text/javascript" charset="utf-8"></script>
    <script src="lib/vertx/vertx-eventbus.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>

<script type="module">
    const eventBus = new EventBus('http://localhost:80');
    eventBus.enableReconnect(true);
    eventBus.send("ping", {ping: 42}, {token:"MyToken"}, (error, response) => {
        console.log("pong");
    });
</script>
<h1>Strange test</h1>
</body>
</html>

异常原因分析

该异常是WebSocket协议层面的校验错误:根据WebSocket规范,客户端发送给服务器的所有数据帧必须使用掩码加密,而服务端收到了未掩码的帧,因此抛出CorruptedWebSocketFrameException。

具体到你的场景,核心问题有两个:

  1. 客户端发送时机错误:在type="module"的脚本中直接调用eventBus.send,此时EventBus尚未完成与服务器的握手连接,提前发送的请求不符合WebSocket帧格式要求。
  2. 服务端路由冲突:重复配置StaticHandler且SockJS路由与静态文件路由匹配规则重叠,导致SockJS请求可能被静态文件处理器错误拦截,引发异常帧。

修复方案

1. 调整客户端代码:等待连接就绪后发送事件

修改客户端脚本,监听EventBus的onopen事件,确保连接成功后再发送请求,同时避免type="module"带来的执行上下文问题:

<!DOCTYPE html>
<html lang="de">
<head>
    <script src="lib/vertx/sockjs.min.js" type="text/javascript" charset="utf-8"></script>
    <script src="lib/vertx/vertx-eventbus.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<script type="text/javascript">
    // 初始化EventBus,指定明确的SockJS路径前缀(与服务端对应)
    const eventBus = new EventBus('http://localhost:80/eventbus');
    eventBus.enableReconnect(true);

    // 连接成功后执行发送逻辑
    eventBus.onopen = function() {
        console.log("EventBus 连接成功");
        eventBus.send("ping", {ping: 42}, {token:"MyToken"}, (error, response) => {
            if (error) {
                console.error("发送失败:", error);
            } else {
                console.log("pong:", response);
            }
        });
    };

    // 监听连接错误
    eventBus.onerror = function(error) {
        console.error("EventBus 连接异常:", error);
    };
</script>
<h1>Strange test</h1>
</body>
</html>

2. 修复服务端路由配置:避免路由冲突

调整服务端路由顺序,给SockJS指定明确的路径前缀,确保SockJS请求优先被处理,同时移除重复的StaticHandler配置:

public class Strange extends AbstractVerticle {

    private HttpServer server;

    @Override
    public void start() throws Exception {
        server = this.getVertx().createHttpServer();
        final Router router = Router.router(this.getVertx());
        router.route().handler(BodyHandler.create());
        
        // 优先配置SockJS路由,指定路径前缀/eventbus
        final SockJSBridgeOptions opts = new SockJSBridgeOptions()
                .addInboundPermitted(new PermittedOptions().setAddressRegex(".*"))
                .addOutboundPermitted(new PermittedOptions().setAddressRegex(".*"));
        final SockJSHandler sockJSHandler = SockJSHandler.create(this.getVertx());
        final var socks = sockJSHandler.bridge(opts, event -> {
            if (event.type() == BridgeEventType.SOCKET_CREATED) {
                log.atInfo().log("Socket was created ...");
            }
            event.complete(true);
        });
        // 给SockJS指定专属路径,避免与静态文件冲突
        router.route("/eventbus/*").subRouter(socks);
        
        // 最后配置静态文件处理器
        router.route().handler(StaticHandler.create());
        
        server.requestHandler(router);
        server.listen(80);
    }

    @Override
    public void stop() throws Exception {
        this.server.close();
    }
}

验证说明

完成上述修改后,客户端会在EventBus连接成功后发送事件,服务端能正确接收符合WebSocket规范的掩码帧,同时路由配置避免了请求拦截问题,异常将不再出现。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 23:47:37