解决Thruway+Autobahn.js的426协议错误,实现WebSocket发布订阅
解决Thruway与Autobahn.js连接的426协议不支持错误
先聊聊你的问题:你已经搭好了Thruway服务器,启动日志看起来完全正常,但浏览器端用Autobahn.js连接时一直弹出「426 No Sec-WebSocket-Protocols requested supported」错误。你查了资料知道Autobahn.js用WAMPv2,旧版Ratchet只支持v1,但Thruway早就支持v2了,这问题到底出在哪?
先看你提供的关键信息:
服务器启动日志
./bin/console thruway:router:start Making a go at starting the Thruway Router 2018-05-23T00:29:33.6760270 debug [Thruway\Peer\Router 17047] New router created 2018-05-23T00:29:33.6830490 info [Thruway\Peer\Router 17047] Starting router 2018-05-23T00:29:33.6853010 info [Thruway\Transport\RatchetTransportProvider 17047] Websocket listening on 127.0.0.1:9998 2018-05-23T00:29:33.6864550 info [Thruway\Transport\RatchetTransportProvider 17047] Websocket listening on 127.0.0.1:9999 2018-05-23T00:29:33.6865040 info [Thruway\Peer\Router 17047] Starting loop
浏览器端代码
var connection = new autobahn.Connection({ url: 'ws://127.0.0.1:9999/', realm: 'realm1' }); connection.onopen = function (session, details) { console.info('Connection opened: ' + session + ' | ' + details); }; connection.onclose = function (reason, details) { console.info('Connection closed: ' + reason + ' | ' + details); }; connection.open();
版本信息
~ composer show -D sensio/distribution-bundle v5.0.21 Base bundle for Symfony Distributions sensio/framework-extra-bundle v5.1.6 This bundle provides a way to configure your controllers with annotations sensio/generator-bundle v3.1.7 This bundle generates code for you symfony/monolog-bundle v3.2.0 Symfony MonologBundle symfony/phpunit-bridge v4.0.9 Symfony PHPUnit Bridge symfony/polyfill-apcu v1.8.0 Symfony polyfill backporting apcu_* functions to lower PHP versions symfony/swiftmailer-bundle v3.2.2 Symfony SwiftmailerBundle symfony/symfony v3.4.9 The Symfony PHP framework thruway/pawl-transport 0.5.0 Pawl WebSocket Transport for Thruway Client voryx/thruway-bundle 0.3.1 WebSockets (WAMP2) integration for Symfony2
Autobahn版本为18.3.2
问题根源
错误426的核心是客户端请求的WebSocket子协议服务器不支持。Autobahn.js 18.3.2默认会向服务器请求wamp.2.json(WAMPv2的JSON序列化协议),但你的Thruway路由器(通过RatchetTransportProvider)并没有明确启用这个子协议支持——虽然Thruway本身支持WAMPv2,但默认配置可能没开对应的子协议。
解决方案
方案1:修改ThruwayBundle配置,启用WAMPv2子协议
打开Symfony的配置文件(比如app/config/config.yml),在Thruway的配置里给Ratchet传输层明确指定支持的子协议:
thruway: router: realms: - name: realm1 roles: anonymous: authorize: true publish: true subscribe: true call: true register: true transports: - type: ratchet listen: 127.0.0.1:9999 subprotocols: - wamp.2.json
保存后重启Thruway路由器,这样服务器就会响应客户端的wamp.2.json子协议请求了。
方案2:在Autobahn.js中明确指定子协议
如果不想改服务器配置,也可以在客户端连接时指定只请求服务器支持的子协议:
var connection = new autobahn.Connection({ url: 'ws://127.0.0.1:9999/', realm: 'realm1', subprotocols: ['wamp.2.json'] // 明确指定只使用WAMPv2 JSON子协议 }); connection.onopen = function (session, details) { console.info('Connection opened: ' + session + ' | ' + details); }; connection.onclose = function (reason, details) { console.info('Connection closed: ' + reason + ' | ' + details); }; connection.open();
angularWAMP使用示例
如果你的项目是基于AngularJS的,angularWAMP确实是个不错的选择,以下是完整的简单示例:
- 安装angularWAMP
通过npm安装:
npm install angular-wamp --save
- 配置AngularJS应用
在你的主模块中引入并初始化angularWAMP:
angular.module('myWebSocketApp', ['vxWamp']) .config(function($wampProvider) { $wampProvider.init({ url: 'ws://127.0.0.1:9999/', realm: 'realm1', subprotocols: ['wamp.2.json'] // 同样指定子协议 }); }) .run(function($wamp) { // 应用启动时打开连接 $wamp.open(); });
- 在控制器中使用订阅/发布
angular.module('myWebSocketApp').controller('NotificationController', function($scope, $wamp) { // 订阅服务器推送的事件 var subscription = $wamp.subscribe('com.notifications.new', function(args) { // 收到推送后更新视图 $scope.notifications.push(args[0]); // 因为WAMP回调在Angular上下文之外,需要手动触发digest循环 $scope.$apply(); }); // 手动发布事件(示例) $scope.sendNotification = function(message) { $wamp.publish('com.notifications.new', [message]); }; // 页面销毁时取消订阅 $scope.$on('$destroy', function() { subscription.unsubscribe(); }); });
额外检查建议
- 可以尝试更新ThruwayBundle到0.4.x版本,新版本的配置更清晰,bug也更少;
- 确认浏览器没有被插件(比如广告拦截器)拦截WebSocket连接;
- 检查服务器端口是否开放,没有被防火墙拦截。
内容的提问来源于stack exchange,提问作者trogwar




