Node.js发送POST请求时遭遇ERR_TLS_CERT_ALTNAME_INVALID错误求助
问题原因与安全解决方案
核心问题:Node.js请求配置错误导致TLS主机名校验失败
先看你给出的错误信息:Host: api.example.com. is not in the cert's altnames,注意主机名末尾多了个.——这是关键线索。再对照你的请求代码,发现你犯了一个典型的配置错误:把host、port、path这些核心请求参数放到了headers对象里,这完全不符合Node.js https.request()的配置规范!
Node.js的https.request()方法中,host、port、path是options的顶级属性,不属于请求头的范畴。当前的错误配置会引发两个问题:
- Node.js在TLS握手阶段,无法正确识别要验证的目标主机名,错误解析出带末尾
.的主机名,和证书的SAN(备用主题名称)不匹配 - 手动在请求头里设置
Host字段,格式不符合HTTP规范,进一步干扰了TLS校验逻辑
而curl能正常工作,是因为它会自动解析你指定的域名,在TLS握手时用标准格式的主机名匹配证书SAN,不会出现配置错误的问题。
安全解决方案:修正请求配置
把host、port、path从headers中移出来,作为options的顶级属性,同时修正代码里的大小写错误(res.Statuscode应该是res.statusCode),另外还可以去掉多余的decodeURIComponent调用(qs.stringify()已经完成了URL编码,解码反而会导致参数格式错误)。修改后的代码如下:
const https = require('https'); const qs = require('querystring'); function PostReq() { let chunks = [], resData = ''; const postData = qs.stringify({ property1: 'value1', property2: 'value2' }); const options = { host: 'api.example.com', path: '/base', port: 443, method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'Content-Length': Buffer.byteLength(postData), } }; const reqPost = https.request(options, (res) => { res.setEncoding('utf8'); if (res.statusCode === 200) { console.log('got successfull http response'); res.on('data', (chunk) => { console.log('getting chunks...'); chunks.push(chunk); }); res.on('end', () => { resData = Buffer.concat(chunks).toString(); console.log('response body data: ', resData); }); } else { console.error('received http status code: ', res.statusCode); } }); reqPost.write(postData); reqPost.on('error', (err) => { console.error('error: ', err); }); reqPost.end(); } PostReq();
额外排查点(若修正后仍有问题)
如果按上述配置修改后还是报错,需要确认两个点:
- 用
openssl s_client -connect api.example.com:443命令查看证书信息,确认api.example.com确实在证书的SAN列表中 - 检查Nginx反向代理的
server块,确保server_name正确设置为api.example.com,且配置了对应的Let's Encrypt证书文件
不过根据你描述的curl能正常请求的情况,大概率是Node.js的配置错误导致的,修正后应该就能解决问题,完全不需要关闭rejectUnauthorized(这个选项关闭会带来中间人攻击的风险,绝对不建议在生产环境使用)。
内容的提问来源于stack exchange,提问作者Setz
相关产品推荐
相关产品推荐

