IIS 8.5 で ARR 3.0 を使用してこれと同じことを達成しようとしていたところ、最終的に問題が見つかりました。Microsoft の Erez Benari によると、これは可能です:
WebSocket をサポートするには、IIS に WebSocket 機能をインストールする必要がありますが、その他の構成やアクションは必要ありません。サーバー マネージャーの [役割と機能の追加] を使用して機能をインストールします。それが完了すると、ARR 3.0 は要求を適切に処理します。
テストとして、WebSocket 用の Node.js サーバーをセットアップしました。
const WebSocketServer = require('ws');
const wss = new WebSocketServer({ ポート: 3011 });
関数 sendWSMessage(msg) {
wss.clients.forEach((クライアント) => {
client.send(メッセージ);
});
}
setInterval(関数() {
sendWSMessage('こんにちはクライアント');
}、3000);
簡単なテストページとともに:
var websock = new WebSocket('ws://localhost:3011');
websock.onmessage = 関数 (イベント) {
console.log(イベント.データ);
};
websock.onopen = 関数 (イベント) {
websock.send("こんにちはサーバー");
};
次に、ローカル マシンに ARR リバース プロキシを設定します。ローカルホストの「wstest」ディレクトリの web.config ファイルに次のように記述します。
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="WebSocketTestRule" stopProcessing="true">
<match url=".*" />
<conditions>
<add input="{CACHE_URL}" pattern="^(.+)://" />
</conditions>
<action type="Rewrite" url="{C:1}://localhost:3011/" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>
//localhost/wstest
これにより、ポート 3011 の Node.js サーバーにすべてのトラフィックが転送されますws://localhost:3011
。経由でプロキシ経由ws://localhost/wstest
で接続しようとすると、リクエストが Node.js サーバーに到達し、アップグレードが行われ、接続が確立されます。
Chrome が送信するもの:
ws://localhost/wstest HTTP/1.1 を取得します。
ホスト: ローカルホスト
接続: アップグレード
プラグマ: no-cache
キャッシュ制御: キャッシュなし
アップグレード: ウェブソケット
オリジン: file://
Sec-WebSocket-バージョン: 13
ユーザーエージェント: Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (Gecko のような KHTML) Chrome/51.0.2704.84 Safari/537.36
Accept-Encoding: gzip、deflate、sdch
Accept-Language: en-US,en;q=0.8
Sec-WebSocket キー: 4ufu8nAOj7cKndASs4EX9w==
Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits
Node.js サーバーは以下を受け取ります。
キャッシュ制御: キャッシュなし
接続: アップグレード
プラグマ: キャッシュなし
アップグレード: ウェブソケット
受け入れエンコード: gzip、deflate、sdch
受け入れる言語: en-US,en;q=0.8
ホスト: ローカルホスト:3011
最大転送: 10
ユーザーエージェント: Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (Gecko のような KHTML) Chrome/51.0.2704.84 Safari/537.36
オリジン: ファイル://
秒-websocket-バージョン: 13
sec-websocket-key: fBkTwAS9d/unXYKDE3+Jjg==
sec-websocket-extensions: permessage-deflate; client_max_window_bits
x-original-url: /wstest
x-転送-for: [::1]:54499
x-arr-log-id: a0b27458-9231-491d-b74b-07ae5a01c300
Node.js サーバーは次のように応答します。
HTTP/1.1 101 スイッチング プロトコル
アップグレード: ウェブソケット
接続: アップグレード
Sec-Websocket-Accept: yep8mgQACAc93oGIk8Azde4WSXk=
Sec-WebSocket-Extensions: permessage-deflate
最後に、Chrome は以下を受け取ります。
HTTP/1.1 101 スイッチング プロトコル
アップグレード: ウェブソケット
Sec-WebSocket-Accept: CBSM8dzuDoDG0OrJC28nIqaw/sI=
Sec-WebSocket-Extensions: permessage-deflate
X-Powered-By: ARR/3.0
接続: アップグレード
X-Powered-By: ASP.NET
日付: 2016 年 6 月 10 日 (金) 21:16:16 GMT
終了時間: 17:16:16.148
受信バイト: 0
送信バイト: 0
だから今、彼らはつながっています。これはすべて問題ないように見えます。唯一の顕著な違いは、Sec-WebSocket-Key と Sec-WebSocket-Accept が IIS または ARR プロキシによって両方向で変更されることです。
しかし... WebSocket フレームがプロキシを通過することはありません! Chrome は、アップグレード リクエストに対して肯定的なフィードバックを受け取ると、WebSocket メッセージ フレームを送信し、サーバーからのメッセージを待っています。Node.js サーバーはそのフレームを送信し、エラーは発生しませんが、Chrome で受信されることはありません。Chrome が送信したメッセージが Node.js によって受信されることはありません。ARR/IIS が WebSocket フレームを両方向にドロップしているようです。
メッセージごとの圧縮用の WebSocket 拡張機能である permessage-deflate 拡張機能をサポートしていることを、Chrome がサーバーにどのように伝えているかに注意してください。サーバーは、permessage-deflate もサポートしていると応答しているため、ブラウザーとサーバーがメッセージを相互に送信するときに、この圧縮拡張機能を使用します。ただし、真ん中の人、ARR は、明らかにこの圧縮をサポートしていません。サーバーで permessage-deflate のサポートをオフにすることで、実際の WebSocket フレームが問題なくプロキシを通過できるようになりました。
const wss = new WebSocketServer({ ポート: 3011, perMessageDeflate: false });
Sec-Websocket-Extensions
問題は、ARR 3.0 がヘッダーをサポートしていないため、ヘッダーが単純に通過できるようになっていることだと思います。しかし、ARR はネゴシエーションに関与せず、圧縮されたメッセージの受け渡しをサポートしていないことを 2 つの当事者に伝える方法がないため、クライアントとサーバーの間でこのヘッダーのネゴシエーションを許可するのは正しくありません。願わくば、いつの日か、ARR がそれ自体とクライアントの間でネゴシエーションを行い、その後、ARR とサーバーの間で別のネゴシエーションを行うことによって、拡張機能を適切に処理できるようになることを願っています。現在のところ、クライアントとサーバーが相互にネゴシエートしているだけで、このエラーが発生します。