Windows Server 2019下ARR 3反向代理配置Socket.IO时出现WebSocket握手错误:Sec-WebSocket-Accept头值不正确
I’ve run into this exact issue before when setting up Socket.IO behind ARR, so let’s break down why this happens and how to fix it. The root problem is that ARR doesn’t properly handle the WebSocket upgrade handshake by default, which mangles the Sec-WebSocket-Accept header validation Socket.IO relies on.
Here’s a step-by-step solution:
1. Enable WebSocket Proxy in ARR
First, make sure ARR is configured to proxy WebSocket traffic correctly:
- Open IIS Manager, select your server node.
- Double-click Application Request Routing.
- Click Server Proxy Settings in the right-hand pane.
- Check the box labeled Enable WebSocket Proxy and click Apply.
This tells ARR to forward WebSocket upgrade requests as-is instead of treating them like regular HTTP requests.
2. Adjust URL Rewrite Rules to Preserve Critical Headers
Your reverse proxy rule needs to retain WebSocket-specific headers during the handshake. Edit your existing rewrite rule:
- Go to your site in IIS, open URL Rewrite.
- Select your rule for
/projectand click Edit. - Navigate to the Server Variables section.
- Add these variables (ensure they’re allowed in ARR’s server variable list if you haven’t configured this before):
HTTP_UPGRADE(set value to{HTTP_UPGRADE})HTTP_CONNECTION(set value to{HTTP_CONNECTION})X-Forwarded-Proto(if using HTTPS, set value to{HTTPS}to pass the correct protocol to your Node.js server)
These headers are non-negotiable for a successful WebSocket handshake between the client and your internal service.
3. Update Socket.IO Client Configuration to Match Proxy Path
Since you’re proxying through /project, your Socket.IO client needs to target the correct endpoint path. Update your client code:
// For external clients connecting to the full domain const socket = io('https://www.mywebsite.com/project', { path: '/project/socket.io', transports: ['websocket', 'polling'] // Prioritize WebSocket over fallback polling }); // For pages hosted directly under /project (relative path) const socket = io({ path: '/project/socket.io' });
Without setting this path, the client will try to connect to /socket.io instead of /project/socket.io—ARR won’t route this correctly, leading to handshake failures.
4. Verify ARR Uses HTTP 1.1 for Proxying
WebSocket requires HTTP 1.1, so double-check this setting:
- In the Server Proxy Settings (from step 1), ensure Use HTTP 1.1 is checked (this is default, but it’s worth confirming).
5. Debug with Browser DevTools (If Issues Persist)
If you’re still stuck, use your browser’s Network tab to inspect the WebSocket request:
- Filter for the "WS" protocol to find the handshake request.
- Compare request headers (like
Sec-WebSocket-Key) between internal direct access and external proxy access. - Validate that the
Sec-WebSocket-Acceptresponse header matches the expected value (calculate it by appending the magic string258EAFA5-E914-47DA-95CA-C5AB0DC85B11to theSec-WebSocket-Keyand base64 encoding the result). If ARR modifies this key, that’s the root of the problem.
After making these changes, restart your IIS site and test external access again—this should resolve the handshake error.
内容的提问来源于stack exchange,提问作者Santhosh Kumar

