升级Node.js至18.0.0后HTTPS环境下SignalR连接失败求助
Node.js 18+ 连接 .NET 8 SignalR HTTPS 失败问题解决办法
客户端代码
index.js
const signalR = require("@microsoft/signalr"); // 禁用TLS验证即可正常运行 // process.env["NODE_TLS_REJECT_UNAUTHORIZED"] = 0; let connection = new signalR.HubConnectionBuilder() .withUrl("https://myapp.mydomain.com:5000/messageHub", // .withUrl("http://myapp.mydomain.com:5002/messageHub", // 使用HTTP时可正常运行 { withCredentials: false }) .withAutomaticReconnect() .configureLogging(signalR.LogLevel.Information) .build(); connection.logging = true; async function start() { try { await connection.start({ withCredentials: false }); console.log("SignalR Connected."); } catch (err) { console.log(err); setTimeout(start, 5000); } }; connection.onclose(async () => { await start(); }); start();
package.json
{ "name": "Client", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], "author": "", "license": "ISC", "dependencies": { "@microsoft/signalr": "8.0.0" } }
相关现象
- Node.js 17.9.1及更早版本运行正常,升级至18.0.0及之后版本连接失败
- 使用HTTP而非HTTPS时可正常运行
- 禁用TLS验证(设置
process.env["NODE_TLS_REJECT_UNAUTHORIZED"] = 0;)能运行,但不希望采用该方式
错误信息
[2024-02-08T11:06:44.246Z] Error: Failed to complete negotiation with the server: TypeError: fetch failed [2024-02-08T11:06:44.246Z] Error: Failed to start the connection: Error: Failed to complete negotiation with the server: TypeError: fetch failed FailedToNegotiateWithServerError: Failed to complete negotiation with the server: TypeError: fetch failed at HttpConnection._getNegotiationResponse (C:\dev\20240227electron\node_modules\@microsoft\signalr\dist\cjs\HttpConnection.js:257:35) at process.processTicksAndRejections (node:internal/process/task_queues:95:5) at async HttpConnection._startInternal (C:\dev\20240227electron\node_modules\@microsoft\signalr\dist\cjs\HttpConnection.js:170:41) at async HttpConnection.start (C:\dev\20240227electron\node_modules\@microsoft\signalr\dist\cjs\HttpConnection.js:73:9) at async HubConnection._startInternal (C:\dev\20240227electron\node_modules\@microsoft\signalr\dist\cjs\HubConnection.js:135:9) at async HubConnection._startWithStateTransitions (C:\dev\20240227electron\node_modules\@microsoft\signalr\dist\cjs\HubConnection.js:112:13) at async Timeout.start [as _onTimeout] (C:\dev\20240227electron\index.js:18:9) {
解决办法
1. 指定可信CA证书
Node.js 18+ 默认启用更严格的TLS证书验证逻辑,如果服务器使用自签名证书或内部CA颁发的证书,需在连接配置中显式指定CA证书:
const signalR = require("@microsoft/signalr"); const fs = require('fs'); const https = require('https'); let connection = new signalR.HubConnectionBuilder() .withUrl("https://myapp.mydomain.com:5000/messageHub", { withCredentials: false, httpsAgent: new https.Agent({ ca: fs.readFileSync('/path/to/your/ca-certificate.pem') }) }) .withAutomaticReconnect() .configureLogging(signalR.LogLevel.Information) .build();
替换/path/to/your/ca-certificate.pem为实际的CA证书文件路径。
2. 检查服务器TLS协议版本
Node.js 18+ 移除了对TLS 1.0、TLS 1.1的支持,确保服务器配置使用TLS 1.2或更高版本。可通过以下命令验证服务器TLS配置:
openssl s_client -connect myapp.mydomain.com:5000
3. 确保证书链完整
服务器需正确配置完整的证书链(包含根证书、中间证书),Node.js 18+ 对证书链完整性的验证更严格,缺失中间证书会导致验证失败。
4. 通过fetch选项传递TLS配置
如果SignalR客户端使用fetch API发起请求,可通过fetchOptions传递TLS代理配置:
.withUrl("https://myapp.mydomain.com:5000/messageHub", { withCredentials: false, fetchOptions: { agent: new https.Agent({ ca: fs.readFileSync('/path/to/ca-certificate.pem') }) } })
内容的提问来源于stack exchange,提问作者George Vovos
相关产品推荐
相关产品推荐

