---
title: "PageBand"
description: "把 dist 拖进浏览器就上线，拿到一个子域名和一次性密码，下次凭密码覆盖更新。"
canonical: https://yonnia.com/projects/pageband
language: zh
status: active
year: 2026
stack: ["Cloudflare Workers","R2","D1","React"]
homepage: https://pageband.com
---
# PageBand

把 dist 拖进浏览器就上线，拿到一个子域名和一次性密码，下次凭密码覆盖更新。

上传一个 `dist` 文件夹，几秒后它在一个 `*.pageband.com` 的子域名上。没有账号，没有 CI，没有配置文件。

## 为什么收敛成一个 Worker

原本的设计是 Cloudflare Pages 放前端、另一个 Worker 管 API。这个方案在写到一半时被一个事实推翻：**Pages 不支持通配符自定义域名**，而这个产品的全部意义就是 `*.pageband.com`。

于是三种角色进了同一个 Worker——产品首页、发布接口、以及用户发布出来的站点——按 `Host` 分流。这不是对简洁的偏好，是唯一可行的形状。

## 10 毫秒

免费版 Worker 每次调用有 10ms CPU 和 50 个子请求的上限。一个真实的 `dist` 有几百个文件，所以「把 zip 传给服务端解压」这条路直接不通：解压本身就会超时，逐个写 R2 也会超子请求数。

所以解压发生在浏览器里。前端拆开 zip，然后每个文件一个 `PUT` 直接流进 R2，六路并发。Worker 每次调用只做一件事——校验签名，把一个流转给 R2。CPU 时间就此和文件数量脱钩。

## 密码而不是账号

没有登录。发布成功时返回一个一次性密码，下次拿「项目名 + 子域名 + 密码」覆盖上传，服务端只存加盐哈希。

这里有一个看起来像偷懒的决定：哈希是单轮 SHA-256，不是 bcrypt 或 argon2。理由是密码由服务端生成，约 93 bits 熵。慢 KDF 防的是人类选的弱密码被离线爆破，而在这个熵下爆破本来就不可行，慢哈希只会吃掉那 10ms 预算的绝大部分。如果哪天允许用户自选密码，这个结论立刻失效。

## 代价

发布链路没法自动化测试。页面上有人机校验，脚本拿不到有效 token，所以端到端套件里涉及完整发布的 14 项断言只能跳过，靠人工回归覆盖。这是为「不需要账号、又不被机器人刷满」付的价。

第二个代价在浏览器那侧：解压和并发上传都跑在用户的机器上，一个几百兆的 `dist` 会让标签页明显卡一下。服务端的 CPU 预算是省下来了，成本转移到了客户端，而不是消失了。
