当我们使用Node.js中的https模块发送请求时,有时会遇到一个CERT_UNTRUSTED的报错问题,这是因为我们请求的是一个自签名的网站证书,而Node.js默认不信任这类证书。本攻略将介绍如何完美解决这个问题。
问题原因
在https请求过程中,客户端会验证服务器的证书是否信任。如果服务器证书是由权威机构颁发的,那么客户端会信任该证书;如果是自签名的证书,则需要客户端手动信任。
解决方案
方法一:忽略证书验证
我们可以使用以下代码忽略证书验证,跳过报错问题。
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
在发送请求前,加入这句代码即可。
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
https.get('https://example.com', (res) => {
// 处理响应数据
});
虽然这个方法可以解决问题,但会影响到所有HTTPS请求的安全性,不建议在生产环境中使用。
方法二:添加自定义证书
该方法可以在不影响其他HTTPS请求的前提下,解决证书信任问题。具体步骤如下:
- 首先,需要获取待请求网站的证书。可以使用openssl命令来获取证书信息,比如:
bash
$ openssl s_client -connect example.com:443 -showcerts
该命令会输出该网站的证书信息,将每个证书的内容(包含 BEGIN CERTIFICATE 和 END CERTIFICATE )复制到一个文本文件中,保存为 example.com.pem 。
- 在Node.js代码中使用该证书:
```javascript
const https = require('https');
const fs = require('fs');
const options = {
hostname: 'example.com',
port: 443,
path: '/',
method: 'GET',
ca: fs.readFileSync('example.com.pem')
};
const req = https.request(options, (res) => {
// 处理响应数据
});
req.end();
```
在options中,我们通过指定ca字段,告诉Node.js使用该自定义证书来验证服务器证书。注意,该字段的值应该是证书文件的内容,可以使用fs.readFileSync()方法来读取。
- 如果你的证书中使用了密码,这里还需要指定证书密码:
javascript
const options = {
...
key: fs.readFileSync('example.com.key'),
passphrase: 'your_password',
ca: fs.readFileSync('example.com.pem')
};
至此,我们已经完美解决了Node.js中使用https请求报CERT_UNTRUSTED的问题。
示例说明
示例一
在此示例中,我们先使用方法一来发送请求获取百度首页的HTML文本。
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
https.get('https://www.baidu.com', (res) => {
let chunks = [];
res.on('data', (chunk) => {
chunks.push(chunk);
});
res.on('end', () => {
const html = Buffer.concat(chunks).toString();
console.log(html);
});
}).on('error', (e) => {
console.error(e);
});
运行该示例,会看到报错信息:
Error: certificate has expired
at TLSSocket.onConnectSecure (_tls_wrap.js:1510:34)
at TLSSocket.emit (events.js:315:20)
at TLSSocket._finishInit (_tls_wrap.js:936:8)
at TLSWrap.ssl.onhandshakedone (_tls_wrap.js:710:12) {
code: 'CERT_HAS_EXPIRED'
}
可以看到,这是由于百度证书已经过期,导致无法验证。现在,我们使用方法二来发送请求获取百度首页HTML文本:
const https = require('https');
const fs = require('fs');
const options = {
hostname: 'www.baidu.com',
port: 443,
path: '/',
method: 'GET',
ca: fs.readFileSync('baidu.com.pem')
};
const req = https.request(options, (res) => {
let chunks = [];
res.on('data', (chunk) => {
chunks.push(chunk);
});
res.on('end', () => {
const html = Buffer.concat(chunks).toString();
console.log(html);
});
});
req.end();
我们首先使用openssl s_client命令获取了百度的证书信息,并将每个证书的内容保存到baidu.com.pem文件中。然后,我们在代码中指定该文件作为自定义证书,发送请求。运行该示例,会成功获取到百度首页的HTML文本。
示例二
我们再来一个示例,这次是请求一个使用了密码的自签名证书的网站。我们需要按照方法二的步骤来发送请求。
const https = require('https');
const fs = require('fs');
const options = {
hostname: 'example.com',
port: 443,
path: '/',
method: 'GET',
key: fs.readFileSync('example.com.key'), // 证书私钥
passphrase: 'your_password', // 证书密码
ca: fs.readFileSync('example.com.pem') // 证书内容
};
const req = https.request(options, (res) => {
let chunks = [];
res.on('data', (chunk) => {
chunks.push(chunk);
});
res.on('end', () => {
const html = Buffer.concat(chunks).toString();
console.log(html);
});
});
req.end();
注意,这里我们需要指定证书的私钥路径和密码,才能成功发送请求。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:完美解决node.js中使用https请求报CERT_UNTRUSTED的问题 - Python技术站