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

将可正常运行的Curl命令转为Node.js原生HTTPS请求时遇SSL错误求助

问题描述

我有一条可正常运行的Curl命令:

curl -vvv "https://<URL>:<port>" --cert /etc/identity/client/certificates/client.pem --key /etc/identity/client/keys/client-key.pem --cacert /etc/identity/ca/cacerts.pem --capath /etc/identity/client/certificates

但转换为Node.js原生https请求时,出现如下错误:

Http is failed. error: Error: write EPROTO 140452300855232:error:1408F10B:SSL routines:ssl3_get_record:wrong version number:../deps/openssl/openssl/ssl/record/ssl3_record.c:332:

我的Node.js实现:
选项配置:

options = {
  hostname:'url',
  path: 'path',
  method: 'GET',
  port: port,
  cert: [fs.readFileSync('/etc/identity/client/certificates/client.pem'), {encoding: 'utf-8'}],
  key: [fs.readFileSync('/etc/identity/client/keys/client-key.pem'), {encoding: 'utf-8'}],
  ca: [fs.readFileSync('/etc/identity/ca/cacerts.pem'), {encoding: 'utf-8'}]
};

请求代码:

https.request(options, res => {...do something})

我能想到的唯一差异是Curl命令有4个证书相关参数(cert、key、cacert、capath),而Node.js的https库仅能传入3个。请问有什么解决思路吗?

解决思路

1. 修复Node.js证书配置的格式错误

你当前的cert、key、ca配置格式完全错误:

  • fs.readFileSync的编码参数需要直接作为第二个参数传入,不需要用数组包裹
  • 正确的证书内容应该是字符串或Buffer,而非数组格式

修正后的配置:

const options = {
  hostname: '<URL>',
  path: '<path>',
  method: 'GET',
  port: <port>,
  cert: fs.readFileSync('/etc/identity/client/certificates/client.pem', 'utf-8'),
  key: fs.readFileSync('/etc/identity/client/keys/client-key.pem', 'utf-8'),
  ca: fs.readFileSync('/etc/identity/ca/cacerts.pem', 'utf-8')
};

2. 处理curl的--capath参数

Node.js的https模块没有直接对应capath的选项,但capath的作用是让OpenSSL从指定目录加载额外CA证书,可通过两种方式替代:

  • 方式一:合并目录内CA证书到单个文件
    把/etc/identity/client/certificates下所有PEM格式证书合并到cacerts.pem中,Node.js通过ca参数即可加载所有证书:
    cat /etc/identity/client/certificates/*.pem >> /etc/identity/ca/cacerts.pem
    
  • 方式二:代码遍历目录读取所有证书
    编写代码遍历目标目录,读取所有PEM文件并组成数组传入ca参数:
    const fs = require('fs');
    const path = require('path');
    
    function loadCAPath(capath) {
      return fs.readdirSync(capath)
        .filter(file => file.endsWith('.pem'))
        .map(file => fs.readFileSync(path.join(capath, file), 'utf-8'));
    }
    
    const options = {
      hostname: '<URL>',
      path: '<path>',
      method: 'GET',
      port: <port>,
      cert: fs.readFileSync('/etc/identity/client/certificates/client.pem', 'utf-8'),
      key: fs.readFileSync('/etc/identity/client/keys/client-key.pem', 'utf-8'),
      ca: [
        fs.readFileSync('/etc/identity/ca/cacerts.pem', 'utf-8'),
        ...loadCAPath('/etc/identity/client/certificates')
      ]
    };
    

3. 排查SSL版本不匹配问题

你遇到的wrong version number错误,大概率是证书配置错误导致SSL握手失败。修复上述配置后仍有问题的话,可以尝试指定服务端支持的SSL协议版本:

const options = {
  // ...其他配置
  secureProtocol: 'TLSv1_2_method' // 可根据服务端实际支持调整为TLSv1_3_method等
};

内容的提问来源于stack exchange,提问作者Dudi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 11:50:30