将可正常运行的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
相关产品推荐
相关产品推荐

