I have a simple NodeJS app like the below
index.js

const signalR = require("@microsoft/signalr");

//Works if I disable TLS validation
//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", //works if I use 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 17.9.1(或更早版本)上工作正常,在 node 18.0.0(或更高版本)上失败
  • 如果我使用http而不是HTTPS,它会起作用
  • 如果我禁用TLS验证,它会起作用,但我当然不想这样做 process.env["NODE_TLS_REJECT_UNAUTHORIZED"] = 0;

我的服务器在.NET 8上使用SignalR 8.

当我运行应用程序node index.js时,我收到

[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) {

有什么主意吗?

推荐答案

这最终是一个证书问题.显然,在 node 18之前,有一个备用选项,在该选项中,如果它最初由于上述问题而无法连接,它将依靠SSE协议,该协议不寻找证书验证.当时没有意识到这是一个问题,因为它通过使用回退选项来工作.根据 node 18和更高版本,现在需要从Windows应用store 导入证书,然后通过以下代码将其添加为受信任的CA

const ca = require('win-ca')

var tls = require('tls');

const rootCAs = [];

export default function addExtraCA(){

fetch().then(render)

}

function fetch() {

var list = []

return new Promise(resolve => {

ca({

async: true,

format: ca.der2.txt,

ondata: list,

onend: resolve

})

})

.then(_ => list)

}

function render(list) {

for (let pem of list) {

var crt= pem.substring(pem.indexOf('-----BEGIN CERTIFICATE-----'));

var buf = Buffer.from(crt, 'utf8');

console.log(buf);

process.env.NODE_EXTRA_CA_CERTS = \${buf}``

addDefaultCA(crt)

}

const origCreateSecureContext = tls.createSecureContext;

tls.createSecureContext = function(options) {

var c = origCreateSecureContext.apply(null, arguments);

if (!options.ca && rootCAs.length > 0) {

rootCAs.forEach(function(ca) {

// add to the created context our own root CAs

c.context.addCACert(ca);

});

}

return c;

};

}

function addDefaultCA(file) {

try {

var content = file

content = content.replace(/\r\n/g, "\n"); // Handles certificates that have been created in Windows

var regex = /-----BEGIN CERTIFICATE-----\n[\s\S]+?\n-----END CERTIFICATE-----/g;

var results = content.match(regex);

if (!results) throw new Error("Could not parse certificate");

results.forEach(function(match) {

var cert = match.trim();

rootCAs.push(cert);

});

} catch (e) {

if (e.code !== "ENOENT") {

console.log("failed reading file " + file + ": " + e.message);

}

}

}

Node.js相关问答推荐

如何在Node.js 中设置图表js的背景色

如何在MongoDB中更新嵌套数组

MongoDB如果文档S的字段小于另一个字段,则将该字段加一

Node-Red Tasmota 错误:连接 ECONNREFUSED 192.168.77.21:1883

如果我加入另一个公会且我的​​机器人已在其中,欢迎消息发送错误

将 POST 的 json 变量格式化为 lambda

动态设置元数据,无需重复请求 NextJS 13

为什么运行 yarn 命令会出错 - yargs-parser的完整性判断失败

如何修改这个flake.nix,这样我就不用每次加载环境都加载nix包了

在 nodejs 中使用 multer 上传文件返回未定义的 req.file 和空的 req.body

FirebaseCloudMessaging : PlatformException (PlatformException(null-error, Host platform returned null value for non-null return value., null, null))

在 Express.js 中迭代子文档数组

为什么在调用数据库调用时我的参数没有定义?

突然 React 无法执行create-react-app命令.为什么会发生这种情况,我该如何解决?

如何使动态私有IP地址静态?

如果我使用像 express 这样的 node 服务器,是否需要 webpack-dev-server

适用于 Windows 7 的 NodeJS

从 zip 文件在 AWS 中创建 lambda 函数

node.js 在控制台上显示未定义

如何调试 Gulp 任务?