我们正在开发一个仅在现代浏览器(IE10 +)上运行的Web应用程序,原因各不相同。
我们实现的功能之一是Socket.io 1.x.但是,默认情况下,Socket.io客户端会尝试支持较旧的浏览器,因此它会启动与长轮询的连接,然后将其更新到WebSockets。这是浪费时间和资源,因为我们知道浏览器支持WS。
我已经四处寻找了,我只能找到this wiki page,但是,这是关于Socket.io 0.9。
最终,我找到the documentation for engine.io-client(Socket.io-client基于1.x分支)。这是我写的代码,似乎正在工作。但是,我想知道它是否正确或者我是否做错了什么:
io.connect('https://...', {
upgrade: false,
transports: ['websocket']
})
奇怪的是,仅将transports
属性设置为websockets
的数组只是不够;我还必须禁用upgrade
。这是对的吗?
我做了一些新的发现。
仅transports
设置为['websocket']
,启用upgrade
时不会产生任何差异。这是正常的吗?
答案 0 :(得分:53)
有两种类型的"升级"发生在socket.io上。首先(在socket.io 1.0+中),socket.io启动所有与http轮询请求的连接,它实际上可能只用一个http请求交换一些初始数据。然后,在此之后的某个时刻,它将尝试实际启动webSocket连接。 webSocket连接是通过发送指定upgrade: websocket
标头的特定类型的http请求来完成的,然后服务器可以适当地响应它是否支持websocket。如果服务器同意升级,那么该特定的http连接将被升级"到webSocket协议。此时,客户端知道webSocket受支持并且它停止使用轮询http请求,从而完成其upgrade
到webSocket。
您可以通过在客户端上执行此操作来完全阻止初始http轮询:
var socket = io({transports: ['websocket'], upgrade: false});
这将阻止来自您自己的合作客户端的轮询连接。如果要阻止任何客户端使用轮询,则可以将其添加到服务器:
io.set('transports', ['websocket']);
但是,如果您在服务器上设置此项,则最初使用http轮询连接的socket.io客户端根本不起作用。因此,这应该只与客户端中的正确设置匹配,以便客户端永远不会以轮询开始。
这将告诉两端你只想使用webSockets而socket.io将在开头跳过额外的http轮询。公平警告,这样做需要webSocket支持,所以这排除了与尚未支持webSocket的旧版IE兼容。如果你想保持兼容性,那么就让socket.io最初用几个http请求来做这件事。
以下是有关协议从http升级到webSocket的更多信息。
webSockets协议使用HTTP连接启动每个webSocket。这就是所有webSockets的工作方式。该HTTP连接包含一些标题,表明浏览器会像#34;升级到webSockets协议。如果服务器支持该协议,则它会响应告知客户端它将升级到webSocket协议,然后该套接字将从HTTP协议切换到webSocket协议。这就是webSocket连接的设计方式。因此,您看到以HTTP连接开头的webSocket连接的事实是100%正常。
您可以将socket.io配置为永远不会使用长轮询,如果这让您感觉更好,但这不会改变webSocket连接仍然以HTTP连接开始然后升级到webSocket协议的事实,它将会不提高支持webSockets的现代浏览器的操作效率。但是,它会使您的连接无法在旧版浏览器中使用。
答案 1 :(得分:29)
要告诉Socket.IO首先只使用WebSocket而不是几个XHR请求,只需将其添加到节点服务器:
io.set('transports', ['websocket']);
在客户端上添加:
var socket = io({transports: ['websocket']});
这告诉Socket.IO只使用WebSocket协议而不是别的;它更干净,更快,并且在客户端和服务器端使用更少的资源。
现在,您只会在网络请求列表中看到一个WebSocket连接,请记住IE9和早期版本不能使用WebSocket。
答案 2 :(得分:19)
我发布了答案,因为接受的答案不正确 - 它将Socket.IO从长轮询AJAX升级到WebSocket与WSS协议“连接:升级”请求混淆。问题不在于WebSocket连接是以HTTP身份启动并升级到WebSocket - 它怎么可能不是? - 但是,即使在支持WebSocket的浏览器上,Socket.IO也会以长轮询AJAX连接开始,并且只在交换一些流量后才进行升级。在Firefox或Chrome的开发者工具中很容易看到。
该问题的作者在他的观察中是正确的。 Socket.IO中的“升级”并不是指HTTP到WSS协议升级,因为它经常被误解,而是指从长轮询AJAX连接升级到WebSocket的Socket.IO连接。如果您已经开始使用WebSocket(这不是默认设置),那么升级false无效,因为您不需要升级。如果您从轮询开始并禁用升级,那么它将保持这种状态,并且不会升级到WebSocket。
如果您想避免以长轮询开始,请参阅 arnold 和 Nick Steele 的答案。我将更详细地解释发生了什么。
这是我在my experiments中使用简单的WebSocket和Socket.IO应用程序观察到的:
从这2个请求中:
(连接升级请求在具有101切换协议响应的开发人员工具上可见。)
根据这6项要求:
我在localhost上获得的WebSocket结果:
我在localhost上获得的Socket.IO结果:
我发布了代码on npm和on GitHub,您可以自行运行:
# Install:
npm i -g websocket-vs-socket.io
# Run the server:
websocket-vs-socket.io
并遵循限制。要卸载:
# Uninstall:
npm rm -g websocket-vs-socket.io
有关详细信息,请参阅this answer。
答案 3 :(得分:8)
我认为我应该添加上面接受的答案,好像有人想要消除XHR轮询传输并立即启动websockets。下面的代码只是为了说明实现:
var url = serverUrl + "/ssClients" //ssClients is the socket.io namespace
var connectionOptions = {
"force new connection" : true,
"reconnection": true,
"reconnectionDelay": 2000, //starts with 2 secs delay, then 4, 6, 8, until 60 where it stays forever until it reconnects
"reconnectionDelayMax" : 60000, //1 minute maximum delay between connections
"reconnectionAttempts": "Infinity", //to prevent dead clients, having the user to having to manually reconnect after a server restart.
"timeout" : 10000, //before connect_error and connect_timeout are emitted.
"transports" : ["websocket"] //forces the transport to be only websocket. Server needs to be setup as well/
}
var socket = require("socket.io-client")(url, connectionOptions);
socket.on("connect", function (_socket) {
logger.info("Client connected to server: " + clientName);
logger.info("Transport being used: " + socket.io.engine.transport.name);
socket.emit("join", clientName, function(_socketId) { //tell the server the client name
logger.info("Client received acknowledgement from server: " + _socketId);
logger.info("Transport being used after acknowledgement: " + socket.io.engine.transport.name);
});
});
设置服务器后,您将看到:
2015-10-23T19:04:30.076Z - info: Client connected to server: someClientId
2015-10-23T19:04:30.077Z - info: Transport being used: websocket
2015-10-23T19:04:30.081Z - info: Client received acknowledgement from server: aMH0SmW8CbiL8w5RAAAA
2015-10-23T19:04:30.081Z - info: Transport being used after acknowledgement: websocket
如果你不强迫运输,你会看到“轮询”而不是websocket。但是,这不会仅在客户端发生,服务器也必须设置:
var io = require("socket.io")(server, { adapter: adapter, log: false }); //attach io to existing Express (http) server
..
io.set('transports', ['websocket']); //forces client to connect as websockets. If client tries xhr polling, it won't connect.
<强>危险强>
如果客户端确实不支持websocket协议,则不会发生连接,客户端将报告xhr poll error
。
这对我来说非常合适,因为我可以控制我拥有的客户,因此我可以立即强制使用websockets,我相信这是原始问题所要求的。我希望这可以帮助那些人...