错误信息
unable to get local issuer certificate
也可能输出为
- code: 'UNABLE_TO_GET_ISSUER_CERT_LOCALLY'
- UNABLE_TO_GET_ISSUER_CERT_LOCALLY
使用 fetch() 时,这条消息作为“TypeError: fetch failed”的原因出现;npm 把同样的情况报告为“npm error code UNABLE_TO_GET_ISSUER_CERT_LOCALLY”。如果服务器只发送叶子证书,Node.js 报告的则是“unable to verify the first certificate”。
Node.js tls / https / fetch — code UNABLE_TO_GET_ISSUER_CERT_LOCALLY (OpenSSL X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY, 20)
含义
服务器发送了证书链(叶子证书和中间证书),但链顶端的证书由 Node.js 不信任的根证书签发。默认情况下,Node.js 只信任编译进二进制文件的 Mozilla 根证书列表,而不信任操作系统的证书存储,因此安装在机器上的公司根证书对它来说是不可见的,除非你让 Node.js 使用它。
原因
公司 CA 或私有 CA
常见内部 API、预发布环境和服务网格使用的根证书不在 Node.js 内置的 Mozilla 列表中。
执行 TLS 检查的代理
常见在公司网络中,拦截代理用公司根证书为公共网站重新签名;如果代理只发送签发用的中间证书,Node.js 报告的就是这个代码,而不是“self-signed certificate in certificate chain”。
Node.js 默认忽略操作系统的证书存储
偶见用 update-ca-certificates 安装根证书,或将其安装到 Windows 证书存储或 macOS 钥匙串中,可以修复 curl 和浏览器的问题,但修复不了 Node.js,除非使用了 --use-system-ca 或 NODE_USE_SYSTEM_CA=1。
修复方法
- 1.
NODE_EXTRA_CA_CERTS
让 Node.js 指向一个 PEM 文件,其中的证书会添加到内置根证书中。该变量只在进程启动时读取一次,因此在正在运行的应用内部导出它不会产生任何效果。
bash # Adds to Node's built-in roots; read once at start-up, so set it before node starts export NODE_EXTRA_CA_CERTS=/etc/ssl/private-ca/corp-root-ca.pem node app.js - 2.
使用操作系统的证书存储
--use-system-ca(或环境中的 NODE_USE_SYSTEM_CA=1)让 Node.js 信任操作系统所信任的证书,而这正是 IT 部门管理的内容。
bash # Trust what the operating system trusts (Windows store, macOS Keychain, Linux bundle) node --use-system-ca app.js # or, for tools that start node themselves (npm scripts, CLIs): NODE_USE_SYSTEM_CA=1 npx some-cli - 3.
在代码中设置默认 CA 列表
tls.setDefaultCACertificates() 会替换默认列表,此后由 https、tls 和 fetch 建立的连接都会使用新列表;如示例所示,把现有的默认证书与你的根证书合并。
js // In code, before the first request: keep the default roots and add yours. // Applies to https, tls and fetch. Available in current Node.js 22 and 24 releases. import tls from "node:tls"; import fs from "node:fs"; tls.setDefaultCACertificates([ ...tls.getCACertificates("default"), fs.readFileSync("/etc/ssl/private-ca/corp-root-ca.pem", "utf8"), ]); - 4.
只为一个 Agent 信任该根证书
Agent 或 tls.connect() 的 ca 选项会替换这些连接的默认根证书;如果同一个 Agent 还要访问公共主机,就要把 tls.rootCertificates 一并加入。
js // Per-agent trust: note that "ca" REPLACES the default roots, so append them import https from "node:https"; import tls from "node:tls"; import fs from "node:fs"; const agent = new https.Agent({ ca: [...tls.rootCertificates, fs.readFileSync("corp-root-ca.pem", "utf8")] }); https.get("https://api.example.com/", { agent }, (res) => res.resume());
相关错误
unable to verify the first certificateNode.js tls / https / fetchself-signed certificate in certificate chainNode.js tls / https / fetchnpm error code UNABLE_TO_GET_ISSUER_CERT_LOCALLYnpm (Node.js)[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local…Python ssl module (OpenSSL)