原文:Node.js 官方指南《Enterprise Network Configuration》。原作者为 Node.js 文档贡献者;版权属于 OpenJS Foundation 与 Node.js contributors。2026-10-05 核对并中文整理,原站网站仓库采用 MIT 许可,完整许可见文末。

企业环境常要求应用经由 HTTP/HTTPS 代理访问外部服务,并使用企业内部证书颁发机构(CA)签发的证书。Node.js 的环境变量、命令行开关和内置网络 API 可以处理不少这样的场景。这里有两项独立工作:让请求经过正确的代理,以及让 TLS 客户端信任经过核准的 CA。设置好其中一项,不代表另一项也已完成。
先核对版本,再选择接口
原指南包含多个不同时间加入的功能,不能笼统写成“Node.js 22 都支持”。以下按原指南当前列出的范围整理;具体发行线仍应查对应版本的 API 文档。
| 功能 | 原指南列出的最低版本 |
|---|---|
| node:http / node:https 环境代理 | v22.21.0 或 v24.5.0+ |
| fetch() 环境代理 | v22.21.0 或 v24.0.0+ |
| –use-env-proxy 开关 | v22.21.0 或 v24.5.0+ |
| 指南中的系统 CA 启用方案 | v22.19.0 或 v24.6.0+ |
补充核对:TLS API 文档标明 tls.getCACertificates() 加入于 v23.10.0 / v22.15.0,tls.setDefaultCACertificates() 加入于 v24.5.0 / v22.19.0。能读取 CA 列表不代表能重设默认列表;示例应按所用方法逐一核验。
一、通过环境变量启用代理
很多公司已由运维设置 HTTP_PROXY、HTTPS_PROXY 和 NO_PROXY。在支持的 Node.js 版本中,还需通过 NODE_USE_ENV_PROXY 或 --use-env-proxy 启用其内置环境代理行为。下面是 POSIX shell 写法,地址均为需要替换的示意值:
export HTTP_PROXY=http://proxy.company.com:8080
export HTTPS_PROXY=http://proxy.company.com:8080
export NO_PROXY=localhost,127.0.0.1,.company.com
export NODE_USE_ENV_PROXY=1
node app.js
也可以保留三个代理变量,把最后两行换成 node --use-env-proxy app.js。原文还展示使用 --env-file:
# .env 中的示例配置
HTTP_PROXY=http://proxy.company.com:8080
HTTPS_PROXY=http://proxy.company.com:8080
NO_PROXY=localhost,127.0.0.1,.company.com
NODE_USE_ENV_PROXY=1
node --env-file ./.env app.js
在支持的接口与版本中,启用后 http、https 和 fetch() 默认采用这些代理设置;显式覆盖 Agent 或命中 NO_PROXY 时,需要按对应接口的规则另行判断。这里 HTTPS_PROXY 的值使用 http://,表示到代理的协议,不等于目标服务已经从 HTTPS 变成明文 HTTP。
二、为单个请求或全局 Agent 指定代理
原文使用 https.Agent({ proxyEnv: ... }) 为 https.request() 及其上层方法指定代理。下面保留这一核心配置,同时补齐请求生命周期;它是编辑修订版,未执行。目标地址和代理地址仍是配置示意。
import https from 'node:https';
const agent = new https.Agent({
proxyEnv: { HTTPS_PROXY: 'http://proxy.company.com:8080' },
});
const req = https.request({
hostname: 'www.external.com',
port: 443,
path: '/',
method: 'GET',
agent,
}, (res) => {
console.log('status:', res.statusCode);
res.on('error', (error) => {
console.error('response error:', error.code ?? 'UNKNOWN');
});
res.on('end', () => agent.destroy());
res.on('close', () => agent.destroy());
res.resume(); // 此示例不使用正文,仍消费响应以释放连接
});
req.setTimeout(10_000, () => req.destroy(new Error('request timeout')));
req.on('error', (error) => {
console.error('request error:', error.code ?? 'UNKNOWN');
agent.destroy();
});
req.end();
原页的 https.request() 片段没有调用 req.end(),也没有展示响应消费和错误处理。上面增加了这些步骤,并给单次示例的 Agent 明确收尾。超时值是编辑示意,setTimeout 是 socket 空闲超时机制,不能当作覆盖 DNS、排队及整段生命周期的统一总时限。服务中的共享连接池应按应用生命周期管理,不能照搬这里每次请求都销毁的做法。
若要更换原生 HTTP/HTTPS 接口的全局 Agent,原文做法是:
import http from 'node:http';
import https from 'node:https';
http.globalAgent = new http.Agent({
proxyEnv: { HTTP_PROXY: 'http://proxy.company.com:8080' },
});
https.globalAgent = new https.Agent({
proxyEnv: { HTTPS_PROXY: 'http://proxy.company.com:8080' },
});
之后使用这些默认 Agent 的请求会受影响,而显式传入其他 Agent 的请求需要另查。这些 globalAgent 不影响 fetch()。原页同时提供 CommonJS 与 ESM 写法;本文统一为 ESM,CommonJS 项目应改用对应的 require('node:http') 和 require('node:https')。
三、认证代理与 NO_PROXY 的边界
原文展示在代理 URL 的 userinfo 部分放入用户名和密码。它是一种配置语法,不适合把真实密码写进教程、源代码、普通日志或提交到仓库的 .env。认证值应由受控的秘密管理机制提供,并避免输出含凭据的 URL;本文没有嵌入任何真实凭据。
NO_PROXY 是绕过代理的规则,而非目标访问白名单。原指南列出以下形式:
| 表达式 | 原指南含义 |
|---|---|
* |
所有主机绕过代理 |
company.com |
精确主机名 |
.company.com |
域名后缀,匹配 sub.company.com |
*.company.com |
通配域名 |
192.168.1.100 |
精确 IP |
192.168.1.1-192.168.1.100 |
IP 范围 |
company.com:8080 |
主机名与特定端口 |
这些模式应在目标 Node.js 版本和实际请求接口上核验。不要把某个失败请求的临时修复扩大为 *,也不要假设主机名、子域、IP 与端口的匹配方式完全相同。
四、从系统证书库或 PEM 文件添加 CA
原指南描述的默认行为是使用随 Node.js 捆绑的 Mozilla 根 CA,而不是自动照搬操作系统证书库。因此,企业 CA 即使已经安装到系统,也可能出现 self signed certificate in certificate chain。在支持的版本中可以显式启用系统 CA:
NODE_USE_SYSTEM_CA=1 node app.js
# 或
node --use-system-ca app.js
启用后,系统 CA 与捆绑 CA 一同用于验证。Windows 读取 Windows Certificate Store,macOS 读取 Keychain;Linux 使用 OpenSSL 默认位置或相关 SSL_CERT_FILE / SSL_CERT_DIR 配置,实际路径取决于 OpenSSL 构建。信任策略仍受平台与 Node.js 规则约束。
如果只要添加一组特定 CA,可以通过一个包含一张或多张 PEM 编码证书的文件配置:
export NODE_EXTRA_CA_CERTS=/path/to/company-ca-bundle.pem
node app.js
也可以同时设置 NODE_USE_SYSTEM_CA=1 与 NODE_EXTRA_CA_CERTS,使默认信任包含捆绑 CA、系统 CA 和额外文件中的证书。证书来源和信任用途应先确认,不能为消除报错随意下载未知 CA。
官方命令行文档还说明:NODE_EXTRA_CA_CERTS 只在 Node.js 进程启动时读取;程序启动后修改 process.env.NODE_EXTRA_CA_CERTS 不会改变当前进程的信任。显式传入 ca 时,默认和额外 CA 不会自动使用;setuid root 或带 Linux file capabilities 等情况下还存在忽略该变量的限制。
五、用程序配置默认 CA
若应用确实需要在代码中决定默认信任集合,先读取现有默认值,再把核准的系统证书追加进去:
import tls from 'node:tls';
const currentCerts = tls.getCACertificates('default');
const systemCerts = tls.getCACertificates('system');
tls.setDefaultCACertificates([...currentCerts, ...systemCerts]);
原文随后演示 https.get() 和 fetch() 使用新的默认 CA。这里应在建立相关连接之前完成配置。API 文档指出,该调用仅影响当前 Node.js 线程,HTTPS Agent 已缓存的先前会话不会被重写;它本身是替换默认列表,因此追加行为来自代码中的数组合并,而不是函数自动保留旧值。
六、只为一次请求指定 CA
原文的 ca 选项适用于 tls.connect()、https.request() 及构建在其上的方法,例如 https.get()。它不是 fetch() 的通用逐请求选项。下面把原文省略的 PEM 字符串改成读取一份事先核准的证书文件,并补充响应消费与错误处理:
import https from 'node:https';
import { readFileSync } from 'node:fs';
const specialCerts = readFileSync('/path/to/approved-ca.pem', 'utf8');
const req = https.get({
hostname: 'internal.company.com',
port: 443,
path: '/',
ca: specialCerts, // 有意只信任此文件,替换该请求的默认 CA
}, (res) => {
console.log('status:', res.statusCode);
res.on('error', (error) => console.error(error.code ?? 'RESPONSE_ERROR'));
res.resume();
});
req.setTimeout(10_000, () => req.destroy(new Error('request timeout')));
req.on('error', (error) => console.error(error.code ?? 'REQUEST_ERROR'));
这是编辑修订的静态示例,没有读取本机文件或建立连接。https.get() 会自动结束请求,所以不再额外写 req.end()。若业务确实要保留原默认信任并追加证书,可有意识地把 tls.getCACertificates('default') 与新证书合并后传入 ca;这会扩大该请求的信任范围,应与只信任企业 CA 的目标区分开。
使用前核对与版权
诊断顺序可以从版本与接口开始,接着核对代理、认证、NO_PROXY、CA 来源及请求生命周期。不要用关闭 TLS 校验、扩大代理绕过范围或提升进程权限来掩盖配置问题。本文没有连接企业网络或修改系统信任;所有片段只做静态审核,没有实际测试,也不能据此保证不存在其他漏洞。
来源:Node.js 企业网络配置全文;版本和信任补充取自 TLS API 与 Command-line API。原站版权与商标归属保留,本文翻译整理和补齐代码之处均已注明。
MIT License
Copyright Node.js Website WG contributors. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.













暂无评论内容