KernelRanch
返回文章列表

环境变量与 secrets:把配置和密钥分开管

2026-11-10 #Cloudflare

读完这一篇,你能把 Worker 的配置拆成两堆:可以公开的普通变量放 [vars],敏感令牌用 wrangler secret 注入;本地开发用 .dev.vars 复现同一套变量名;多环境时用 env.production 隔离;并且知道哪些操作会不小心把密钥打出来。

Worker 里取值都走 env:

export default {
  async fetch(request, env) {
    const mode = env.MODE;              // "prod"
    const token = env.API_TOKEN;        // secret,只有值,没有元信息
    return Response.json({ mode, hasToken: Boolean(token) });
  }
};

env 上同时挂着普通变量、secrets 和资源绑定(KV、R2、D1、DO)。名字空间是同一个,所以绑定名和变量名不能撞。

1. 两种东西的区别

[vars]secrets
写在哪wrangler.tomlwrangler secret put,不落配置文件
是否进 Git会,明文不会
控制台能否看到值能不能,只能看到名字
改动方式改文件后重新 deploy命令执行后立即生效
适合放什么环境名、开关、公开的 API 基址token、数据库密码、第三方密钥

判断标准很简单:这个值泄漏了会不会造成损失。会,就是 secret。

2. 普通变量

name = "cf64-env-demo"
main = "src/index.js"
compatibility_date = "2026-10-08"

[vars]
MODE = "prod"
API_BASE = "https://api.example.com"
FEATURE_NEW_UI = "true"

注意 FEATURE_NEW_UI 写的是字符串 "true" 而不是布尔 true。TOML 允许写 true,但到了运行时 env.FEATURE_NEW_UI 一定是字符串,和布尔比较会失败:

// 错:env.FEATURE_NEW_UI 是 "true",不是 true
if (env.FEATURE_NEW_UI === true) { /* 永远不成立 */ }

// 对
if (env.FEATURE_NEW_UI === "true") { /* 成立 */ }

数字同理,PORT = 8080 到了 env.PORT 是 "8080",参与运算前要 Number(env.PORT)。这类 bug 不报错、只是分支永远走错,排查起来很费时间。

[vars] 的内容会随部署一起上传,控制台的变量页面里明文可见。改完要重新 wrangler deploy 才生效——这是新手最容易卡住的一点:改完 wrangler.toml 直接刷新页面,看到的还是旧值。

3. secrets

wrangler secret put API_TOKEN
# 交互式粘贴值,回车结束

wrangler secret list          # 只列名字和类型
wrangler secret delete API_TOKEN

也可以从管道喂值,CI 里常用:

echo "$API_TOKEN" | wrangler secret put API_TOKEN

secret list 的输出里只有名字,没有值。这一点是设计使然:写入之后连你自己也读不回来,只能覆盖或删除。丢了就重新生成一个。

secrets 的写入会创建新的 Worker 版本,通常立即对生产流量生效,不需要再跑一次 wrangler deploy。但如果你紧接着又 deploy 了一次旧代码,变量不会丢——secrets 存在 Worker 级别的配置里,不跟代码版本绑定。

本地开发时 secrets 不会自动同步下来。要在本地用,得写进 .dev.vars:

# .dev.vars(这个文件要进 .gitignore)
API_TOKEN=local-dev-token
MODE=dev

wrangler dev 会读它,wrangler deploy 不会上传它。建议同时提交一个 .dev.vars.example 列出需要的变量名,别人克隆下来照抄改名就能跑:

# .dev.vars.example
API_TOKEN=
MODE=dev

4. 多环境

同一份代码部署到测试和生产,用 env 段隔离:

name = "cf64-env-demo"

[vars]
MODE = "prod"

[env.staging]
name = "cf64-env-demo-staging"

[env.staging.vars]
MODE = "staging"

带 [env.xxx] 的配置在部署时用 --env:

wrangler deploy --env staging
wrangler secret put API_TOKEN --env staging

不同环境的 secrets 互相独立,生产和测试可以给不同的 token。这一点比"一个变量里塞两个值再判断"干净得多。

带 [env.xxx] 的环境会有自己的 Worker 名字,wrangler secret put 不加 --env 时只影响顶层那个。排查"改了 secret 没生效"时,第一步是确认改的是哪个环境的。

有个容易混的地方:[env.staging] 是嵌套表,顶层 [vars] 不会自动继承到子环境。要每个环境都有的变量,在每段里各写一次,或者用 --env 之外的配置文件组织。

5. 三个真会踩的坑

第一个是日志。console.log(env.API_TOKEN) 会把密钥写进 Workers Logs 和 wrangler tail 的输出,而 tail 的输出可能被同事、被日志平台、被截图带走。要调试就打印长度或前四位:

console.log("token len", env.API_TOKEN?.length ?? 0);

第二个是错误信息。fetch 失败时把整个请求头塞进 Response.json({ err, headers }),authorization 就跟着进了响应体,再被前端上报到监控平台。序列化前先脱敏。

第三个是本地和线上不一致。.dev.vars 里有 API_TOKEN,线上忘了 wrangler secret put,本地全绿、线上一请求就 500。部署清单里加一条"核对 wrangler secret list",能省掉一次线上故障。

变量名习惯上用全大写加下划线,和环境变量的通用约定一致。名字里别带环境后缀(不要 API_TOKEN_PROD 和 API_TOKEN_STAGING 各写一个),环境区分交给 --env,代码里只认一个名字,切换成本最低。

6. 常见问题

问:[vars] 里的值能是对象或数组吗? 答:不能,只能是字符串。JSON 结构就存成字符串,用的时候 JSON.parse(env.CONFIG)。解析失败要兜底,否则配置写错会让整个 Worker 挂掉。

问:能不能在 Worker 里读 process.env? 答:开了 nodejs_compat 之后有 process.env,但 Worker 的变量注入走的是 env 参数,两者不是同一套。不要依赖 process.env,用 env 是唯一稳定的方式。

问:怎么让 TypeScript 认出 env 的类型? 答:wrangler types 会扫描配置生成 Env 接口,把绑定和变量都写进去。生成的文件可以提交,改了配置再跑一次。

小结

分工按"泄漏了会不会出事"划线:能公开的放 [vars],敏感的走 wrangler secret。运行时都从 env 取,取到的永远是字符串,布尔和数字要自己转。

三个操作习惯能避开大部分问题:改完 [vars] 记得重新 deploy,本地 secrets 写 .dev.vars 并加进 .gitignore,日志和错误响应里不打印密钥原文。多环境用 --env 加独立 secrets,比在代码里判断环境名可靠。本地开发与调试的完整流程见 65-wrangler-dev-debug.md,日志侧的处理见 66-workers-observability.md;变量之外还需要存配置数据时,59-workers-kv-tutorial.md 是更灵活的选择。

数据来源与检索时间

检索时间 2026-11-10。

来源URL对应数据
环境变量与 secretshttps://developers.cloudflare.com/workers/configuration/environment-variables/[vars] 写法、字符串类型约束(未抓取)
Secrets 管理https://developers.cloudflare.com/workers/configuration/secrets/secret put/list/delete、不可回读(未抓取)
本地开发变量https://developers.cloudflare.com/workers/local-development/environment-variables/.dev.vars 的读取规则(未抓取)

核验说明

  • 未部署,未本地运行。本篇没有创建真实 secret,没有执行 wrangler secret put/list,也没有用 .dev.vars 起过 dev 服务。
  • [vars] 只能存字符串、secrets 不可回读、.dev.vars 不上传这三点依据官方文档的通用描述,三页文档都没有抓取,未逐条比对原文。
  • wrangler types 的具体生成内容与文件名没有验证,读者以命令实际输出为准。
  • 第 5 节的三条坑来自常见实践总结,不是本次实测复现。
  • 未做:没有测 secrets 更新后旧版本是否仍能读到旧值,没有测 --env 与顶层 [vars] 的继承边界,没有测 CI 环境下 secret put 的交互行为。