Node.js 内置 fetch 处理自签名证书错误:完整解决方案

主题: node-fetch-self-signed-certificate-error更新于: 2026/7/19作者:AgentFactory 技术团队

快速答案

  • 核心结论:Node.js 18+ 内置 fetch 遇到自签名证书时会抛出 self signed certificate 错误,需要通过 https.Agent 配置 rejectUnauthorized: false 或使用 NODE_EXTRA_CA_CERTS 环境变量解决。
  • 第一排查:确认 Node.js 版本 ≥ 18,检查错误信息是否包含 self signed certificateunable to verify the first certificate
  • 最小修复代码:在 fetch 调用中传入自定义 agent:const agent = new https.Agent({ rejectUnauthorized: false }); fetch(url, { agent })
  • 适用边界:仅限开发/测试环境或内部网络,禁止在生产环境对外部 API 使用此方案。
  • 安全替代方案:使用 NODE_EXTRA_CA_CERTS 环境变量指向自定义 CA 证书文件,而非全局禁用验证。

问题复现与根因分析

当你在 Node.js 18+ 中使用内置 fetch 访问使用自签名证书的 HTTPS 服务器时,会得到类似以下错误:

Error: self signed certificate in certificate chain
    at TLSSocket.onConnectSecure (node:_tls_wrap.js:1530:34)

根因:Node.js 默认使用系统 CA 证书库验证 TLS 连接。自签名证书不在受信任的 CA 列表中,因此连接被拒绝。这与浏览器访问自签名证书网站时显示"您的连接不是私密连接"是同一机制。

解决方案一:使用 https.Agent(推荐)

这是最精确的控制方式,只对特定请求禁用证书验证:

JAVASCRIPT
import { fetch } from 'node-fetch-self-signed-certificate-error';
import https from 'https';

// 创建自定义 agent,允许自签名证书
const agent = new https.Agent({
  rejectUnauthorized: false  // 仅用于开发/测试环境
});

async function fetchInternalAPI() {
  try {
    const response = await fetch('https://internal-server.com/api', { agent });
    const data = await response.json();
    console.log(data);
  } catch (error) {
    console.error('请求失败:', error);
  }
}

关键点

  • rejectUnauthorized: false 告诉 Node.js 跳过证书验证
  • agent 可以复用,避免为每个请求创建新连接
  • 此设置仅影响使用该 agent 的请求,不影响全局

解决方案二:使用 NODE_EXTRA_CA_CERTS 环境变量(生产推荐)

如果你有自签名 CA 证书文件,这是生产环境的最佳实践:

BASH
# 在启动时指定自定义 CA 证书
NODE_EXTRA_CA_CERTS=/path/to/your/custom-ca.pem node app.js

优势

  • 只信任特定的自签名证书,而非所有自签名证书
  • 无需修改代码
  • 适用于所有 HTTPS 请求(包括第三方库)

证书文件格式要求

  • PEM 格式(Base64 编码)
  • 可以包含多个证书(按顺序拼接)
  • 文件扩展名通常为 .pem.crt.cert

解决方案三:全局环境变量(仅限紧急调试)

BASH
# 全局禁用 TLS 验证(极度不推荐)
NODE_TLS_REJECT_UNAUTHORIZED=0 node app.js

警告:这会禁用所有 HTTPS 请求的证书验证,包括对外部服务的请求,存在严重安全风险。仅用于本地快速调试,切勿用于生产环境。

常见报错与排查

错误信息原因解决方案
self signed certificate in certificate chain服务器使用自签名证书使用 https.Agent 设置 rejectUnauthorized: false
unable to verify the first certificate证书链不完整使用 NODE_EXTRA_CA_CERTS 指向包含中间证书的 PEM 文件
certificate has expired证书已过期重新生成自签名证书,检查系统时间
TypeError: fetch is not a functionNode.js 版本 < 18升级 Node.js 或使用 node-fetch 包作为 polyfill

生产环境实践与注意事项

安全建议

  1. 永远不要在生产环境对外部 API 使用 rejectUnauthorized: false
  2. 优先使用 NODE_EXTRA_CA_CERTS 添加自定义 CA
  3. 使用环境变量控制是否启用自签名证书支持:
JAVASCRIPT
const agent = process.env.ALLOW_SELF_SIGNED === 'true'
  ? new https.Agent({ rejectUnauthorized: false })
  : new https.Agent();

Docker 容器中的证书问题

Docker 容器使用最小化基础镜像时可能缺少系统 CA 证书,导致即使使用有效证书也会报错:

DOCKERFILE
# 在 Dockerfile 中安装 CA 证书
FROM node:18-alpine
RUN apk add --no-cache ca-certificates
COPY custom-ca.pem /usr/local/share/ca-certificates/
RUN update-ca-certificates

证书过期处理

自签名证书通常有效期较短,建议:

  • 设置证书过期监控告警
  • 在 CI/CD 流程中自动更新证书
  • 使用证书有效期检查脚本定期验证

常见问题 FAQ

Q: 如何在生产环境中安全地使用自签名证书?

A: 生产环境不建议全局禁用证书验证。最佳实践是将自签名证书添加到系统信任存储或使用 NODE_EXTRA_CA_CERTS 环境变量指向自定义 CA 文件。这样只信任特定证书,而非所有自签名证书。

Q: 为什么在 Docker 容器中运行时会遇到证书错误?

A: Docker 容器通常使用最小化基础镜像,可能缺少系统 CA 证书。解决方案:1) 在 Dockerfile 中安装 ca-certificates 包;2) 使用 COPY 命令将自定义证书复制到容器;3) 设置 NODE_EXTRA_CA_CERTS 环境变量指向证书文件。

Q: 使用 rejectUnauthorized: false 会影响性能吗?

A: 理论上不会显著影响性能,但自定义 agent 可能影响连接池管理。建议复用 agent 实例,避免为每个请求创建新 agent。实际性能差异在大多数场景下可忽略。

相关深度解决方案

在配置当前服务时,如果您需要实现更复杂的架构或多源数据整合,建议配合参考我们整理的 Next.js next.config.js 配置参数详解:从开发到生产的完整指南

在配置当前服务时,如果您需要实现更复杂的架构或多源数据整合,建议配合参考我们整理的 NextAuth CredentialsProvider 错误处理:从 `authorize` 到前端的完整链路