さまざまな理由により、最新のブラウザ(IE10 +)でのみ実行されるWebアプリケーションを開発しています。
実装した機能の1つはSocket.io 1.xです。ただし、デフォルトでは、Socket.ioクライアントは古いブラウザーをサポートしようとするため、長いポーリングで接続を開始してからWebSocketに更新します。ブラウザがWSをサポートしていることは確かであるため、これは時間とリソースの無駄です。
私はあちこち検索しましたが、見つけることができるのは このwikiページ ですが、これはSocket.io 0.9についてです。
最終的に、 engine.io-clientのドキュメント (Socket.io-clientは1.xブランチに基づいています)が見つかりました。これは私が書いたコードで、seems動作しているようです。しかし、私はそれが正しいかどうか、または何か間違ったことをしているかどうかを知りたいです:
io.connect('https://...', {
upgrade: false,
transports: ['websocket']
})
奇妙なことに、transports
プロパティをwebsockets
のみの配列に設定するだけでは不十分でした。 upgrade
も無効にする必要がありました。これは正しいです?
私はいくつかの新しい発見をしました。
transports
を['websocket']
のみに設定すると、upgrade
が有効かどうかに違いはありません。それは正常ですか?
Socket.ioで発生する「アップグレード」には2つのタイプがあります。最初(socket.io 1.0以降)、socket.ioはすべての接続をhttpポーリングリクエストで開始し、実際にはhttpリクエストだけで初期データを交換する場合があります。その後、その後のある時点で、実際にwebSocket接続を開始しようとします。 webSocket接続は、upgrade: websocket
ヘッダーを指定する特定のタイプのhttp要求を送信することで行われ、サーバーはwebsocketをサポートするかどうかに関係なく適切に応答できます。サーバーがアップグレードに同意すると、その特定のhttp接続はwebSocketプロトコルに「アップグレード」されます。その時点で、クライアントはwebSocketがサポートされていることを認識し、ポーリングhttpリクエストの使用を停止し、webSocketへのupgrade
を完了します。
クライアントでこれを行うことにより、最初の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プロトコルは、すべてのwebSocketをHTTP接続で開始します。これがすべてのwebSocketの動作です。そのHTTP接続には、ブラウザがwebSocketsプロトコルへのアップグレードを「希望」することを示すヘッダーがいくつか含まれています。サーバーがそのプロトコルをサポートしている場合、サーバーに応答してwebSocketプロトコルにアップグレードし、そのソケットがHTTPプロトコルからwebSocketプロトコルに切り替わることをクライアントに伝えます。これが、webSocket接続が機能するように設計されている方法です。そのため、HTTP接続で始まるwebSocket接続が表示されるという事実は、100%正常です。
Socket.ioを設定して長時間のポーリングを使用しないように設定できますが、気分が良くなる場合でも、webSocket接続がHTTP接続で開始され、その後webSocketプロトコルにアップグレードされるという事実は変わりません。 webSocketをサポートする最新のブラウザーでの操作の効率。ただし、古いブラウザでは接続が機能しないようにします。
最初にいくつかのXHRリクエストではなくWebSocketのみを使用するようSocket.IOに指示するには、これをNodeサーバーに追加するだけです:
io.set('transports', ['websocket']);
そしてクライアントでこれを追加します:
var socket = io({transports: ['websocket']});
これは、Socket.IOにWebSocketプロトコルのみを使用するように指示します。よりクリーンで高速で、クライアント側とサーバー側で使用するリソースが少し少なくなります。
これで、ネットワーク要求リストに単一のWebSocket接続のみが表示されます。IE9以前ではWebSocketを使用できないことに注意してください。
受け入れられた回答が正しくないため、私はその回答を投稿しています-WSSプロトコル「接続:アップグレード」リクエストで、ロングポーリングAJAXからWebSocketへのSocket.IOアップグレードを混同します。問題は、WebSocket接続がHTTPとして開始され、WebSocketにアップグレードされることではありません。どうしてできないのでしょうか? -ただし、Socket.IOは、WebSocketをサポートするブラウザー上でもロングポーリングAJAX接続で開始され、トラフィックを交換した後にのみアップグレードします。 FirefoxまたはChromeの開発者ツールで簡単に確認できます。
質問の著者は彼の観察で正しいです。 Socket.IOの「アップグレード」は、誤解されることが多いHTTPからWSSへのプロトコルアップグレードではなく、長いポーリングAJAX接続からWebSocketへのSocket.IO接続のアップグレードを指します。すでにWebSocketで起動している場合(これはデフォルトではありません)、アップグレードする必要がないため、falseのアップグレードは効果がありません。ポーリングから開始してアップグレードを無効にすると、そのままでWebSocketにアップグレードされません。
で回避したい場合は、arnoldおよびNick Steeleによる回答を参照してくださいロングポーリング。何が起こっているかをより詳しく説明します。
これは、単純なWebSocketおよびSocket.IOアプリで 私の実験 で観察したことです:
これらの2つのリクエストから:
(接続のアップグレードリクエストは、101スイッチングプロトコルレスポンスで開発者ツールに表示されます。)
これらの6つのリクエストから:
Localhostで取得したWebSocketの結果:
Localhostで取得したSocket.IOの結果:
コードを公開しました npm および GitHub で、自分で実行できます:
# Install:
npm i -g websocket-vs-socket.io
# Run the server:
websocket-vs-socket.io
そして、制限に従ってください。アンインストールするには:
# Uninstall:
npm rm -g websocket-vs-socket.io
詳細については、 この回答 を参照してください。
誰かがXHRポーリングトランスポートを削除し、すぐにWebソケットを開始したい場合のように、上記の受け入れられた答えに追加する必要があると思いました。以下のコードは、実装のアイデアを示すためのものです。
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プロトコルをサポートしないnot場合、接続は行われず、クライアントはxhr poll error
。
私が持っているクライアントを制御できるので、これは私にとって完璧に機能しています。したがって、ウェブソケットをすぐに強制する贅沢があります。これが誰かに役立つことを願っています...