You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何NODE_EXTRA_CA_CERTS在start命令中失效致证书验证失败?

问题:NODE_EXTRA_CA_CERTS环境变量生效异常分析与解决

问题场景

通过两种不同启动命令运行Node.js项目时,虽然均能读取到NODE_EXTRA_CA_CERTS环境变量,但仅其中一种能正常完成HTTPS请求的证书验证,另一种触发证书验证失败错误。

相关代码片段

package.json 片段

"scripts": {
    "work":"cross-env NODE_EXTRA_CA_CERTS=\"..\\CA.cer\" nodemon ./index.js",
    "start": "nodemon -r dotenv/config ./index.js",
    "test": "echo \"Error: no test specified\" && exit 1"
},

.env 文件内容

NODE_EXTRA_CA_CERTS=.\CA.cer 

初始 index.js 核心片段

import axios from "axios";
import 'dotenv/config';
const api = axios.create();

// 响应拦截器
api.interceptors.response.use(
    null, // 默认成功处理
    (error) => {
        return Promise.reject({
            status: error.response?.status,
            message:
                error.response?.data ?? error.response?.statusText ?? error.message,
        });
    },
    {
        synchronous: true, // 优化拦截器处理
    }
);

const fetch = async (data, method, url, responseType, headers) => {
    const requestObj = {
        url,
        method,
        responseType,
        headers,
        [method.toLowerCase() === "get" ? "params" : "data"]: data,
    };
    const response = await api(requestObj); // 使用创建的实例
    if (response.request.responseType === "blob") {
        let fileName = response.headers["content-disposition"];
        fileName = fileName.substring(fileName.indexOf("filename=") + 9);
        const newBlob = new Blob([response.data], {
            type: response.headers.get("content-type"),
        });
        const objUrl = window.URL.createObjectURL(newBlob);
        const link = document.createElement("a");
        link.href = objUrl;
        link.download = fileName;
        link.click();
    }
    return response.data;
};

// ...省略其他代码

console.log(process.env.NODE_EXTRA_CA_CERTS);

try {
    let result = await fetch(null, "get", url,null , header);
} catch (error) {
    console.log("An Error occur:");
    console.log(error.message);
    console.log("==========================================");
}

执行结果对比

  • 执行 npm run work 输出(请求成功):
.\CA.cer
  • 执行 npm run start 输出(请求失败):
.\CA.cer
An Error occur:
unable to verify the first certificate

原因分析

核心问题在于NODE_EXTRA_CA_CERTS环境变量的生效时机:

  • npm run work 中,cross-env 在Node.js进程启动前就设置了环境变量,此时Node.js的TLS模块在初始化阶段会读取该变量并加载指定的CA证书,后续所有HTTPS请求都会自动使用该证书完成验证。
  • npm run start 中,-r dotenv/config 是在Node.js进程启动后才通过dotenv加载环境变量。而Node.js的TLS模块在进程启动初期就已完成CA证书池的初始化,后续设置的NODE_EXTRA_CA_CERTS不会被TLS模块重新读取——变量仅存在于process.env中,但并未真正作用到HTTPS请求的证书验证逻辑里。

解决方法

直接在Axios请求中配置自定义httpsAgent,手动加载CA证书并绑定到请求上,绕开环境变量加载时机的限制。修改后的核心代码如下:

const fetch = async (data, method, url, responseType, headers, httpsAgent) => {
    const requestObj = {
        headers,
        httpsAgent,
        method,
        responseType,
        url,
        [method.toLowerCase() === "get" ? "params" : "data"]: data,
    };
    const response = await api(requestObj); // 使用创建的实例
    if (response.request.responseType === "blob") {
        let fileName = response.headers["content-disposition"];
        fileName = fileName.substring(fileName.indexOf("filename=") + 9);
        const newBlob = new Blob([response.data], {
            type: response.headers.get("content-type"),
        });
        const objUrl = window.URL.createObjectURL(newBlob);
        const link = document.createElement("a");
        link.href = objUrl;
        link.download = fileName;
        link.click();
    }
    return response.data;
};

// 补充导入所需模块
import https from 'https';
import fs from 'fs';

const httpsAgent = new https.Agent({
    ca: fs.readFileSync(process.env.NODE_EXTRA_CA_CERTS),
});
try {
    let result = await fetch(null, "get", url, null, header, httpsAgent);
    console.log(result.count);
} catch (error) {
    console.log("An Error occur:");
    console.log(error.message);
    console.log("==========================================");
}

这种方式直接在请求层面指定CA证书,不受环境变量加载时机限制,能确保HTTPS请求使用指定证书完成验证。


内容的提问来源于stack exchange,提问作者The KNVB

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 21:29:57