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。
具体到你的场景,核心问题有两个:
- 客户端发送时机错误:在
type="module"的脚本中直接调用eventBus.send,此时EventBus尚未完成与服务器的握手连接,提前发送的请求不符合WebSocket帧格式要求。 - 服务端路由冲突:重复配置
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
相关产品推荐
相关产品推荐

