nodejs模拟wss服务提示The subprotocol ‘[object Object]‘ is invalid.的问题分析

参考文档:https://developer.mozilla.org/zh-CN/docs/Web/API/WebSocket/WebSocket

问题结论

先给问题结论,这是由于创建websocket对象时第二个可变参数格式错误导致的:

// 即下面代码中的{ rejectUnauthorized: false }
var ws = new WebSocket('wss://localhost:3000/', { rejectUnauthorized: false });

参考websocket的API可以看到,第二个可变参数的格式应该是字符串或者字符串数组,所以传递一个对象时页面就会提示自协议无效(即The subprotocol ‘[object Object]’ is invalid.)。

问题背景

笔者由于业务开发要求需要在本地搭建一个wss服务供页面调试,在网上找了基于nodejs-websocket的服务端代码(nodejs-websocket版本为1.7.2,证书是通过openssl制作的自签名证书):

var ws = require('nodejs-websocket');
var fs = require('fs');
var options = {
    secure: true,
    key: fs.readFileSync("server.key"),
    cert: fs.readFileSync("server.crt"),
    passphrase: '123456'
};
var server = ws.createServer(options, function (socket) {
    var count = 1;
    socket.on('text', function (str) {
        console.log(str);
        socket.sendText('服务端返回消息:' + count++);
    });
}).listen(3000);

然后是页面代码:

<html></html>
<script>
	var ws = new WebSocket('wss://localhost:3000/');
	
	ws.onopen = function() {
		setInterval(function() {
			ws.send('客户端发送消息');
		},2000);
	}
	ws.onmessage = function(e) {
		console.log(e.data)
	}
</script>

此时运行页面会报错:client.html:4 WebSocket connection to ‘wss://localhost:3000/’ failed: ,且没有具体错误原因。笔者猜测是自签名证书的问题,百度以后还真有挺多文章说在创建websocket对象时第二个参数应该传递{ rejectUnauthorized: false },这样可以忽略自签名证书的校验,因此修改页面代码如下:

<html></html>
<script>
	var ws = new WebSocket('wss://localhost:3000/', { rejectUnauthorized: false });
	
	ws.onopen = function() {
		setInterval(function() {
			ws.send('客户端发送消息');
		},2000);
	}
	ws.onmessage = function(e) {
		console.log(e.data)
	}
</script>

但是照抄过来仍然报错:The subprotocol ‘[object Object]’ is invalid.(不知道是哪个憨憨写的代码,也不跑起来验证一下)。

根因分析

其实初始写的代码是没有问题的,页面报错也确实是由于自签名证书引起的,只是解决方案弄错了。虽然websocket是允许跨域的,但是当服务端使用的是自签名证书时,浏览器仍然会阻止访问,只是不会像访问使用自签名证书的https地址那样有提示且允许忽略。当明确问题后,可以通过下面的方法来规避:

新打开一个页面访问https://localhost:3000/,然后忽略浏览器的安全提示,此时再刷新原来报错的页面可以看到页面显示正常了,websocket也可以正常发送和接收消息了。

注意:上面访问的地址是https,而不是wss。

而网上关于这个问题的解答很少的原因,笔者推测为跨域访问自签名websocket的场景实际基本不存在,因此大家几乎没有遇到这个问题的机会,大多数的业务场景是在自签名的页面中访问同域下的websocket,这样我们在忽略自签名页面的安全提示后,同域下的websocket就不再会被浏览器阻止访问了。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值