通过NodeJS代理在React中连接SignalR失败问题求助
React借助http-proxy-middleware代理SignalR连接失败问题
问题概述
在React应用中使用http-proxy-middleware通过Node.js代理连接SignalR时失败,但直接连接.NET后端SignalR服务一切正常,代理对其他API调用也能正常工作。
React控制台错误日志
[2022-11-29T23:02:24.022Z] Information: Normalizing '/hubs/Chat' to 'https://localhost:3000/hubs/Chat'. [2022-11-29T23:02:24.022Z] Debug: Starting connection with transfer format 'Text'. [2022-11-29T23:02:24.023Z] Debug: Sending negotiation request: https://localhost:3000/hubs/Chat/negotiate?negotiateVersion=1. [2022-11-29T23:02:24.642Z] Debug: Selecting transport 'WebSockets'. [2022-11-29T23:02:24.643Z] Trace: (WebSockets transport) Connecting. WebSocket connection to 'wss://localhost:3000/hubs/Chat?id=DykJoTMv9LiYrtjYHUCQVg' failed: [2022-11-29T23:06:24.671Z] Information: (WebSockets transport) There was an error with the transport. [2022-11-29T23:06:24.672Z] Error: Failed to start the transport 'WebSockets': Error: WebSocket failed to connect. The connection could not be found on the server, either the endpoint may not be a SignalR endpoint, the connection ID is not present on the server, or there is a proxy blocking WebSockets. If you have multiple servers check that sticky sessions are enabled. [2022-11-29T23:06:24.672Z] Debug: Skipping transport 'ServerSentEvents' because it was disabled by the client. [2022-11-29T23:06:24.672Z] Debug: Skipping transport 'LongPolling' because it was disabled by the client. [2022-11-29T23:06:24.672Z] Error: Failed to start the connection: Error: Unable to connect to the server with any of the available transports. Error: WebSockets failed: Error: WebSocket failed to connect. The connection could not be found on the server, either the endpoint may not be a SignalR endpoint, the connection ID is not present on the server, or there is a proxy blocking WebSockets. If you have multiple servers check that sticky sessions are enabled. ServerSentEvents failed: Error: 'ServerSentEvents' is disabled by the client. LongPolling failed: Error: 'LongPolling' is disabled by the client. Error establishing the connection: Error: Unable to connect to the server with any of the available transports. Error: WebSockets failed: Error: WebSocket failed to connect. The connection could not be found on the server, either the endpoint may not be a SignalR endpoint, the connection ID is not present on the server, or there is a proxy blocking WebSockets. If you have multiple servers check that sticky sessions are enabled. ServerSentEvents failed: Error: 'ServerSentEvents' is disabled by the client. LongPolling failed: Error: 'LongPolling' is disabled by the client. at HttpConnection._createTransport (HttpConnection.ts:407:1) at async HttpConnection._startInternal (HttpConnection.ts:283:1) at async HttpConnection.start (HttpConnection.ts:137:1) at async HubConnection._startInternal (HubConnection.ts:207:1) at async HubConnection._startWithStateTransitions (HubConnection.ts:181:1)
React端SignalR连接代码
this.hubConnection = new HubConnectionBuilder() .withUrl("/hubs/chat",{ transport: HttpTransportType.WebSockets, logger: LogLevel.Trace }) .withAutomaticReconnect() .build(); this.hubConnection.start().catch(error => console.log("Error establishing the connection: ", error));
Node.js代理代码(初始版本)
const PORT = 8000; const express = require('express'); const https = require('https'); const fs = require('fs') const {createProxyMiddleware} = require('http-proxy-middleware'); const app = express(); require('dotenv').config({ path: `.env.${process.env.NODE_ENV.trim()}` }); const httpsOptions = { key: fs.readFileSync('./certs/cert.key'), cert: fs.readFileSync('./certs/cert.pem') } app.use('/hubs/chat', createProxyMiddleware({ target: process.env.REACT_APP_APISERVICEURL, changeOrigin: false , secure: false, ws: true, logger: console })); var secure = https.createServer(httpsOptions, app); secure.listen(8000, () => console.log(`Server is running on port ${PORT}`));
尝试过的修改版本(无效)
const signlrRProxy = createProxyMiddleware({ target: process.env.REACT_APP_APISERVICEURL, changeOrigin: false , secure: false, ws: true, logger: console }); app.use('/hubs/chat', signlrRProxy); var secure = https.createServer(httpsOptions, app); secure.listen(8000, () => console.log(`Server is running on port ${PORT}`)); secure.on('upgrade', signlrRProxy.upgrade);
已知信息
- 直接连接.NET后端SignalR服务正常,后端无问题
- 代理对其他API调用正常
- React已在
package.json中设置proxy属性,代理会重写URL并添加API Token头 - 所有依赖包均为最新版本
解决方案
1. 修正changeOrigin配置
将代理配置中的changeOrigin: false改为changeOrigin: true。SignalR的WebSocket握手请求需要正确的Host头,启用changeOrigin会修改请求头的Host为目标服务器的Host,确保后端能正确识别SignalR端点。
2. 检查目标URL的路径格式
确保REACT_APP_APISERVICEURL不包含末尾斜杠及SignalR路径,比如后端SignalR端点是https://your-backend.com/hubs/chat,则目标URL应设为https://your-backend.com,避免代理重复拼接路径导致404。
3. 添加路径重写规则(可选)
如果后端路径与前端请求路径需要映射调整,添加pathRewrite规则确保路径正确传递:
app.use('/hubs/chat', createProxyMiddleware({ target: process.env.REACT_APP_APISERVICEURL, changeOrigin: true, secure: false, ws: true, logger: console, pathRewrite: { '^/hubs/chat': '/hubs/chat' } }));
4. 确保WebSocket升级事件正确绑定
使用HTTPS服务器时,必须将upgrade事件绑定到代理的升级处理函数,完整代码示例:
const PORT = 8000; const express = require('express'); const https = require('https'); const fs = require('fs') const {createProxyMiddleware} = require('http-proxy-middleware'); const app = express(); require('dotenv').config({ path: `.env.${process.env.NODE_ENV.trim()}` }); const httpsOptions = { key: fs.readFileSync('./certs/cert.key'), cert: fs.readFileSync('./certs/cert.pem') } const signalRProxy = createProxyMiddleware('/hubs/chat', { target: process.env.REACT_APP_APISERVICEURL, changeOrigin: true, secure: false, ws: true, logger: console, }); app.use(signalRProxy); const secureServer = https.createServer(httpsOptions, app); secureServer.on('upgrade', signalRProxy.upgrade); secureServer.listen(PORT, () => console.log(`Server is running on port ${PORT}`));
5. 临时启用多传输方式排查
在React端暂时放开其他传输方式,确认是否仅WebSocket代理存在问题:
this.hubConnection = new HubConnectionBuilder() .withUrl("/hubs/chat",{ transport: [HttpTransportType.WebSockets, HttpTransportType.LongPolling], logger: LogLevel.Trace }) .withAutomaticReconnect() .build();
内容的提问来源于stack exchange,提问作者Anthony
相关产品推荐
相关产品推荐

