alias 和 --env

发布于

事情起因很简单。

后台已经部署到 Cloudflare。浏览器打开预览地址,登录成功,跳到 /skills。标签页标题却是:

404 - 后台管理

页面不存在。

可本地同一条路由好好的。侧栏第一项就是技能。账号还是管理员。

于是第一个疑问自然冒出来:

路由明明在,为什么线上说页面不存在?

从一场 404 说起

这套后台拆成两个 Worker。

一个是后台 Web,负责页面和 Cookie 会话。
一个是后台 API,负责 REST。

Web 的 SSR loader 要去拉技能列表。当时的写法很直白:拿环境变量里的公网地址,fetch 过去。

预览环境里,这个地址长这样:

https://feat-admin-api.myaccount.workers.dev/api/admin/skills

我在笔记本上 curl 它,没登录会返回 401。路由在,API 也在。

可从 Web 这个 Worker 里面打过去,得到的是 404。
React Router 把这个 404 当成「当前页面不存在」,于是标签页变成了那行字。

真正的原因在 Fetch 文档里:同账号、同 zone 的 Worker 用全局 fetch 打对方的 workers.dev,请求不会进那个 Worker。它会落到空 origin 上。12

浏览器能打开那个 URL。
Worker 里不行。

所以第二个疑问来了:

两个 Worker 到底该怎么说话?

先换成内网

Cloudflare 给的答案不是再拼一个公网域名,而是 Service Binding。34

调用方 wrangler 里写:

{
  "services": [
    {
      "binding": "ADMIN_API",
      "service": "admin-api"
    }
  ]
}

binding 是自己代码里的名字,env.ADMIN_API.fetch(...)
service 是对方 wrangler 的 name,不是 URL,也不是自定义域名。

这就像 Compose 里的服务名、K8s 里的 ClusterIP:请求不出公网,也不吃同 zone 那条限制。

我改完之后,404 从「页面不存在」变成了另一件事——预览还在,绑定却指错了人。

两种预览

Builds 设置里,非生产分支的版本命令曾经是:

npx wrangler versions upload --env preview

地址栏里看到的却是:

https://feat-admin-web.myaccount.workers.dev

我下意识觉得:--env preview 就是为了生成这个 feat- 前缀。

错了。

这两个东西长得很像,完全不是一回事。

一个是外号。
一个是分身。

alias 是外号

Preview URL 的格式是:

<alias 或版本前缀>-<WORKER_NAME>.<子域>.workers.dev

所以:

feat-admin-web.myaccount.workers.dev

拆开就是:

脚本还是 admin-web
生产的 Active Deployment 不会被换成这个版本。
自定义域名 admin.example.com 也不会指过来。

对应的命令是 Builds 默认的那条:7

npx wrangler versions upload

需要固定外号时,再加 --preview-alias feat

它解决的是:我想看看这个 commit,但别动线上。

env 是分身

--env preview 要 wrangler 里真有一块 env.preview6

没有的话,Wrangler 仍会按命名环境处理,默认把脚本名变成:

<顶层 name>-<环境名>

也就是 admin-web-preview

Dashboard 里会多出一个 Worker。
Hyperdrive、R2、Service Binding、vars、secrets,都不会从顶层继承,得在 env.preview 里再写一遍。8

这是长期活着的 staging,不是 PR 预览。

你可以给它另绑一个域名,用另一套数据库,让后台 Web 的分身去调后台 API 的分身。
代价是账号里 Worker 数量翻倍,绑定要手搓配对。

Binding 跟谁

Service Binding 跟的是 Worker 名,不是 Git 分支,也不是 Preview URL。

走 alias 时:

同分支如果也改了 API,预览 UI 看不到那份 API。Binding 不会自动跟到「这个 PR 的 API preview」。

--env preview 时:

漏写 service,比 404 更危险:页面能开,数据写进生产库。

域名跟谁

自定义域名跟的也是 Worker 名,不是分支名。

走 alias:

--env

之前那个同 zone 404,就是因为用公网 hostname 当「内网 DNS」。
Binding 不认 hostname。域名只负责人从浏览器走进来。自定义域名上的 Worker 互调,规则又不一样。10

这回怎么选

个人站点、PR 只想看页面:

代价很明确:预览 UI 打的是生产 API。

只有这些情况才值得上 env

那是在复制一整套基础设施。
别用最重的模型,去解决最轻的问题。

收束

回到那次 404。

页面没有丢。
是两件独立的事叠在一起:

修第一件,用 Service Binding。
修第二件,把版本命令里的 --env preview 拿掉。

以后再看见 feat-admin-web.….workers.dev,我会先拆一下:

前半段是外号,后半段才是它到底是谁。

参考资料

  1. Fetch · Worker to Worker
  2. Compatibility flag:global_fetch_strictly_public
  3. Limits · Worker-to-Worker subrequests
  4. Service bindings
  5. Wrangler services 配置
  6. Preview URLs
  7. Workers Builds 配置
  8. Wrangler environments
  9. Wrangler 配置 · Environments
  10. Versions and deployments
  11. Custom Domains · Worker to Worker

Footnotes

  1. Fetch:同账号 Worker 互调,要么 Service Binding,要么 global_fetch_strictly_public

  2. Limits:同 zone 无 binding 的 fetch() 会失败。

  3. Service bindings:不经过公网 URL,直接调另一个 Worker。

  4. Wrangler servicesservice 填目标 Worker 名;带环境时为 <name>-<env>

  5. Preview URLs<alias 或版本前缀>-<WORKER_NAME>.<subdomain>.workers.dev

  6. Wrangler environments--env 部署的是另一套 Worker,不是 Preview alias。 2

  7. Workers Builds:非生产分支默认 wrangler versions upload;只有 wrangler 里真有 named environment 才加 --env

  8. 配置 · Environments:bindings 不继承,要在 env.<name> 里重写。

  9. Deployment management:改被调 Worker 的代码,不会给调用方自动出新 version;binding 打的是对方当前部署。

  10. Custom Domains:同 zone 打 Route / workers.dev 会失败;目标挂在 Custom Domain 上则可以。