You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

通过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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 07:25:18