每个 API 团队都会撞上同一堵墙。最初写的请求指向一台服务器,header 里粘一个 token。然后 staging 出现了。然后是生产。突然你每次运行前都要手改 URL,还有人因为前置 URL 过期,把删除接口打到了 prod。API 环境变量就是为了干掉这一整类错误而存在的,Apifox 把它做成产品核心,而不是后来再焊上去。
这篇指南带你在 Apifox 里配好 Dev、Staging、Prod 环境,把 token 和 API key 存成变量而不是硬编码字符串,用本地值把真实密钥留在云端之外,再通过 Apifox CLI 把环境带进 CI。如果想先看「带环境和密钥管理的 API 客户端」应该覆盖什么,我们另有专文。这里直接上手。
为什么硬编码 URL 和 Token 会在第二个环境时崩掉
只有一个环境时,硬编码完全够用。https://api.acmepay.dev 写在每个请求里,token 写在每个 Authorization header 里,暂时什么都不疼。
痛是从第二个环境出现那一刻开始的:
- 每个请求都要改一遍才能换目标。 五十个接口指向 dev,测 staging 就要改五十次 URL,切回来再改五十次。你一定会漏一个。
- Token 会越过边界泄漏。 粘进请求 body 的 prod API key 会随项目保存、跟团队共享、随集合一起导出。Twelve-Factor App 对这件事很直白:配置随部署变化,代码不随部署变化,所以配置绝不该进你拿去分享的产物。
- 运行不再可复现。 URL 和凭证住在每个请求内部时,「对 staging 跑一遍冒烟」就变成一次手动查找替换,而不是一键切换。
修法又老又管用:把请求定义(method、path、body、断言)和部署上下文(前置 URL、凭证、环境相关 ID)拆开。请求在各处保持同一份。变的只有上下文。
Apifox 如何建模环境与变量
Apifox 把问题拆成两块,一起工作。
一个 environment 是具名上下文,比如 Dev、Staging 或 Prod。每个环境带着自己的前置 URL(请求真正发往的服务端)和自己的变量值。切换环境,项目里每个请求会一起改目标,详见 环境管理文档。
一个 variable 是具名占位符,写成 {{variable_name}},可以用在任何填值的地方:URL、query 参数、header、请求 body 和脚本。运行时,Apifox 按当前环境和其它参与的作用域解析这个占位符。
变量作用域,以及谁覆盖谁
Apifox 通过五个作用域解析变量。优先级从低到高:global、module、environment、data、local。
| Scope | Lives where | Typical use |
|---|---|---|
| Global | 整个项目,所有环境 | 像 {{api_version}} 这样的常量 |
| Module | 项目的一个模块 | 微服务项目里按服务区分的设置 |
| Environment | 仅当前环境 | {{base_url}}、{{auth_token}}、{{merchant_id}} |
| Data | 测试运行时的外部 CSV/JSON 文件 | 逐行测试输入 |
| Local (temporary) | 一次请求或一次测试运行,然后消失 | 场景中途提取出来的 token |
优先级在实际工作里很重要。把 {{auth_token}} 定义为全局兜底,到处都能用;但只要 Staging 环境定义了自己的 {{auth_token}},激活 Staging 时环境值就会赢。这正是你要的:下面是共享默认,上面是环境覆盖。各作用域更细的走法,见「在 Apifox 中掌握变量」。
有一个行为容易绊人:本地变量按设计就是临时的。在脚本里 set 一个,运行结束就没了。对测试场景里的临时值这是特性;如果你指望它留下来,那就是心智模型的 bug。明天还要用的东西,应该放进环境变量或全局变量。
在 Apifox 里配置 Dev、Staging、Prod
下面以一套三套部署的支付 API 为例。
1. 创建三个环境
从项目右上角打开环境管理,为每一套部署新建环境。每个环境给一个名字和前置 URL:
Dev→https://api-dev.acmepay.devStaging→https://api-staging.acmepay.devProd→https://api.acmepay.com
前置 URL 带协议、不要末尾斜杠,这样 path 拼接才干净。
2. 每个环境使用同一套变量名
一致性就是全部诀窍。每个环境用不同的值定义同一组变量名:
| Variable | Dev | Staging | Prod |
|---|---|---|---|
{{auth_token}} |
dev token | staging token | prod token |
{{merchant_id}} |
mrc_test_449 |
mrc_stg_449 |
mrc_live_8821 |
{{webhook_secret}} |
dev secret | staging secret | prod secret |
3. 请求里只引用变量,不写裸值
创建一笔 charge 的请求,在任何环境里都长这样:
POST /v1/charges
Authorization: Bearer {{auth_token}}
{
"merchant_id": "{{merchant_id}}",
"amount": 1999,
"currency": "usd"
}
前置 URL 完全不出现;Apifox 会自动把当前环境的前置 URL 拼上去。请求定义里不出现任何环境名,这正是它可移植的原因。
4. 用选择器切换
环境选择器在 Apifox 窗口右上角。选 Staging,项目里每个请求、测试场景和脚本都会按 staging 的前置 URL 和变量值解析。不用改,不用查找替换。如果在权衡各部署档位里该放什么,「sandbox vs 测试环境」那篇对比了团队通常怎么拆。
从 Postman 过来?已有环境可以带过来。「把 Postman 环境和集合迁到 Apifox」会走一遍导入集合和环境,变量值也会一起过来。
把密钥留在本地:共享值 vs 本地值
大多数团队栽在这一段,也是 Apifox 设计真正值钱的地方。
Apifox 里每个环境和全局变量都可以持有两个值,见 变量参考:
- Shared value:与 Apifox 服务器同步,项目里每个人都看得到。
- Local value:只存在你这台机器的客户端缓存里。它不同步到云端,同事也看不到。
两者都有时,客户端用本地值。所以密钥的安全写法很简单:
- 在每个环境里创建变量,例如
{{auth_token}}。 - 共享值留空,或写成
SET_LOCALLY这类占位。 - 把真实 token 放进你自己机器上的本地值。
变量结构会同步给团队。密钥不会。每个工程师把自己的凭证填一次,之后所有共享请求立刻能用。这和 OWASP Secrets Management Cheat Sheet 一致:把密钥的范围收紧,走受控通道分享,别放进会被大范围复制的东西里。
还有两点值得知道。本地值住在客户端缓存里,清掉 Apifox 缓存就会丢,换新笔记本也要重新填。为此预留五分钟,总好过 prod key 同步给十二个人之后花五个小时做事故复盘。
你也可以把整个环境标成私有而不是共享。只有两个负责发布的人能看见 Prod 环境,这是合理设置,再叠上本地值就是纵深防御。
在测试场景和 CI 中使用环境
环境会直接带进 Apifox 的测试场景。场景只建一次(创建 charge、轮询状态、断言结算),执行时再选对着哪个环境跑。同一个场景既是 dev 冒烟,也是 staging 回归套件。
脚本读写的是同一套作用域。从登录响应里抓一个新 token 的后置操作长这样:
const body = pm.response.json();
pm.environment.set("auth_token", body.access_token);
场景里后面的请求会把 {{auth_token}} 解析成刚抓到的值。把请求参数拉进脚本这类写法,见「在前置/后置脚本里读取请求参数」。
CI 里,Apifox CLI 用 flag 接收环境:
apidog run --access-token $APIDOG_ACCESS_TOKEN \
-t 637132 \
-e 358171 \
--env-var "auth_token=$STAGING_API_TOKEN"
-e 按 ID 选择环境。注意 CLI 解析的是共享值,不是你机器上的本地值,这是正确行为:个人密钥本来就不该被构建机碰到。运行时再注入真实凭证,用 --env-var 和 --global-var 以 key=value 形式覆盖,或用 --variables 加载整个文件。真实密钥放在 CI 提供方的密钥库(GitHub Actions secrets、GitLab CI variables)再传进来。流水线里不会出现明文 token,轮换凭证也只需要改一处 CI secret。
由此形成的团队工作流
合在一起,分工很干净:
- 共享、同步:环境名、前置 URL、变量名、占位共享值、测试场景。
- 个人、本地:每个工程师的 token 和 key,作为本地值。
- CI 持有:流水线凭证放在 CI 密钥库,通过 CLI flag 注入。
新同事加入,打开项目,就能看到三个现成环境,每个变量都已命名并写了说明。他们把 dev token 贴进一个本地值字段,立刻开始干活。没有人私聊 prod key。也没有人维护一份会过期的「当前 staging URL」wiki 页。
常见坑
- 把真实 token 写进共享值。 这是最常见的错误。密钥如果必须给同事,走密码管理器或 vault,不要走同步变量。把共享值审计一遍;看起来像活凭证的,都迁到本地值并轮换。
- 忘了当前激活的是哪个环境。 肌肉记忆会在眼睛核对选择器之前就把请求发出去。让破坏性操作更难误触:把
Prod设成更少人可见的私有,给仅生产使用的变量起不同的名字或占位共享值,这样打错环境时会在 auth 上大声失败,而不是悄悄成功。 - 指望临时变量留下来。 运行期间 set 的 local 作用域变量,结束即消失。需要持久的,在脚本里明确提升到环境作用域。
- 各环境变量名不一致。 如果 dev 叫
{{token}}、staging 叫{{auth_token}},一切换环境就会有一半请求挂掉。到处用同一套名字,只让值不同。 - 一个巨型环境装下所有东西。 如果把
dev_base_url和prod_base_url塞进同一个环境,你只是用更多步骤重建了硬编码问题。一个部署上下文对应一个环境。
FAQ
如何避免密钥进入共享的 Apifox 项目?
把它们存成本地值。每个变量都有共享值(同步给团队)和本地值(只缓存在你的机器上)。共享值留成占位,真实 token 放本地。要再隔离一层,把 Prod 这类敏感环境标成私有,只让特定的人看见。
全局变量和环境变量有什么区别?
全局变量作用于整个项目,跟当前激活哪个环境无关;适合部署之间从不变化的值,比如 API 版本字符串。环境变量属于某一个环境,两边定义了同一名字时环境值会赢。「变量指南」拆过全部五个作用域,包括 module、data 和 local。
为什么测试在 Apifox 客户端能过、在 CI 会失败?
通常是因为客户端解析本地值,CLI 解析共享值。token 只存在本地值时,CLI 看到的是空或占位变量。在流水线里显式传入 --env-var "auth_token=$YOUR_CI_SECRET",让 CI 在运行时提供自己的密钥。
能把 Postman 环境迁到 Apifox 吗?
能。Apifox 可以直接导入 Postman 集合和环境,变量名和值都会保留,所以迁移后 {{base_url}} 引用仍然有效。导入后再检查一遍值,把真实凭证迁到本地值——Postman 导出可能以明文带着密钥。
开发必备:API 全流程管理神器 Apifox
介绍完上文的内容,我想额外介绍一个对开发者同样重要的效率工具 —— Apifox。作为一个集 API 文档、调试、设计、测试、Mock、自动化测试于一体的工具,Apifox 是目前提升研发效率的首选。
如果你正在开发项目,不妨试试其极其友好的界面设计,它完全兼容 Postman 和 Swagger 数据格式,导入数据非常方便,,即使是新手也能很快上手,点击这里即可注册使用。

值得一提的是,除了个人和常规团队使用,针对有高安全合规要求、或需要在内网环境协作的企业,Apifox 还提供了深度定制的私有化部署方案。
获取专属报价与部署方案
详细的私有化部署系统架构与安全白皮书
针对您公司规模的专属报价单
免费的 1v1 专属产品演示 (Demo) 机会