WebSocket在Safari浏览器无法连接,其余浏览器可正常使用
解决Safari下WebSocket连接失败的问题
首先你的服务端代码存在一处疏漏:createServer未从http模块引入,正确写法如下:
const express = require('express'); const http = require('http'); // 新增引入http模块 const WebSocket = require('ws'); const app = express(); const server = http.createServer(app); // 修正服务器创建逻辑 const server_socket = new WebSocket.Server({ server: server, path: '/ws' }); server_socket.on('connection', function(ws) { console.log("client joined"); ws.on('error', (error) => {console.error('Error:', error);}); // 建议打印具体错误信息,方便排查 ws.on('close', () => {console.log('client left');}); }); // 补充服务器启动逻辑,示例监听3000端口 server.listen(3000, () => { console.log('Server running on port 3000'); });
针对Safari的连接失败问题,核心原因是permessage-deflate扩展的协商不兼容:Safari发送的sec-websocket-extensions仅包含permessage-deflate,缺少其他浏览器带的client_max_window_bits参数,而ws库默认逻辑可能因此拒绝握手。你可以通过以下两种方式适配:
方式一:禁用permessage-deflate扩展
直接关闭压缩扩展,让所有浏览器使用无压缩的WebSocket连接,绕过扩展协商问题:
const server_socket = new WebSocket.Server({ server: server, path: '/ws', perMessageDeflate: false // 禁用压缩扩展 });
方式二:调整压缩配置兼容Safari请求
如果需要保留压缩功能,可配置ws库接受不带client_max_window_bits的请求:
const server_socket = new WebSocket.Server({ server: server, path: '/ws', perMessageDeflate: { clientNoContextTakeover: true, serverNoContextTakeover: true, clientMaxWindowBits: false // 允许客户端不指定窗口位参数 } });
另外需要排查:
- 服务器防火墙/反向代理(如Nginx)是否拦截了Safari的请求,若使用Nginx需确保WebSocket代理配置正确:
location /ws { proxy_pass http://localhost:3000; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header Host $host; } - 确认不存在混合内容拦截(如页面为HTTPS但WebSocket用ws协议,Safari会拦截此类请求)
内容的提问来源于stack exchange,提问作者Ro Anders
相关产品推荐
相关产品推荐

