KernelRanch
返回文章列表

Pages 与 Workers 静态资源:同一件事的两种做法

2026-11-10 #Cloudflare

读完这篇你能做到:用 wrangler 配置把静态文件和 Worker 代码一起部署,理解请求在什么情况下会进 Worker、什么情况下直接由边缘返回文件,并且能判断手上的项目该放 Pages 还是放 Workers。

两个产品现在都能托管静态文件,配置文件长得很像,额度也不冲突。差别在控制方式和生命周期:Pages 面向"接仓库、自动构建"的工作流,Workers 面向"我自己构建、自己控制每个请求"的工作流。选型的宏观判断在 52-workers-vs-pages.md,这篇讲具体怎么配。

1. 一份配置同时管两者

Workers 的静态资源通过 assets 字段声明,部署时 Worker 代码和文件作为一个整体上传:

{
  "$schema": "./node_modules/wrangler/config-schema.json",
  "name": "my-spa",
  "main": "src/index.js",
  "compatibility_date": "2026-11-10",
  "assets": {
    "directory": "./dist",
    "binding": "ASSETS"
  }
}

directory 指向构建产物,binding 声明一个可在代码里引用的绑定名。写完执行 wrangler deploy,一次操作把代码和文件都推上去。

用 Vite 插件时不需要写 directory,插件会自己填。手写配置的项目把这两项写清楚更省心。

2. 请求怎么走

默认规则只有三条,按顺序判断:

  1. 请求路径能对上 assets 目录里的文件,直接返回该文件,Worker 代码不执行。
  2. 没有对应文件,且存在 Worker 脚本,请求交给 Worker 处理。
  3. 没有对应文件也没有 Worker 脚本,返回 404。

第 1 条是省额度的关键。命中静态文件时既不跑代码也不消耗 CPU,静态资源请求本身不计量。第 2 条意味着"文件不存在"这件事会把流量导向你的代码,写 catch-all 路由时要知道这一点。

Worker 里主动把请求交回静态资源,用绑定:

export default {
  async fetch(request, env) {
    const url = new URL(request.url);
    if (url.pathname.startsWith('/api/')) {
      return Response.json({ ok: true });
    }
    return env.ASSETS.fetch(request);
  },
};

3. 两个开关改变默认行为

not_found_handling 决定文件不存在时怎么办:

取值行为适用
none返回 404,默认值普通多页站点
404-page返回目录里的 404.html有自定义错误页
single-page-application返回 index.html,由前端路由接管React / Vue 的 SPA

SPA 部署最容易出的问题就是刷新子路由得到 404,设成 single-page-application 就好了。代价是任何不存在的路径都返回 200 加首页,接口路径写错时不会看到 404,只能靠日志发现。

run_worker_first 让请求先过 Worker 再决定是否取静态文件。需要按身份改写页面、做灰度、或在返回 HTML 前注入内容时用它,配成路径数组可以只让部分路径前置。

{
  "assets": {
    "directory": "./dist",
    "binding": "ASSETS",
    "not_found_handling": "single-page-application",
    "run_worker_first": ["/admin/*"]
  }
}

开了这个开关之后,命中的路径每请求都会执行代码,静态请求的免费部分不再适用。

4. 与 Pages 的对照

维度PagesWorkers 静态资源
构建平台内置,推仓库即构建自己构建,wrangler deploy 上传
路由控制_routes.json,粒度到路径前缀run_worker_first、not_found_handling
代码入口functions/ 目录,文件即路由单个 main 入口,自己写路由
预览环境每次部署一个预览域,默认就有靠 wrangler versions 与自定义域
配置位置控制台为主wrangler.jsonc 为主
适合内容站、要 push 即部署应用、要精确控制请求

Pages 的 _routes.json 与 Workers 的 run_worker_first 解决的是同一个问题:哪些请求该进代码。前者按包含排除列表描述,后者按路径前缀前置,思路不同。

官方文档侧栏已经把"从 Pages 迁移到 Workers"单独列出来,Pages 的定位转向了存量项目的维护。新项目如果没有历史包袱,直接在 Workers 上做更合适。

5. 迁移时要改的地方

从 Pages 迁到 Workers,改动集中在四块:

代码入口从 functions/ 的多个文件合成一个 main,路由要自己写。用 Hono 这类框架能省掉手写路由的工作,写法见 58-hono-on-workers.md。

构建从平台搬到本地或 CI,wrangler deploy 之前先跑 npm run build。这一步在 53-first-free-site-with-workers.md 里有完整流程。

绑定从控制台改到配置文件,KV、D1、R2 都写进 wrangler.jsonc。

预览环境需要自己搭。Pages 的"每个分支一个地址"没有直接对应物,常见做法是给每个环境部署一个 Worker,或者用版本加自定义域。

常见问题

两个都配了会怎样。

不会同时生效。一个域名只能指向一个 Worker 或一个 Pages 项目,配了两个是两条独立的路由,请求只会命中其中一条。迁移期间可以并行存在,用不同域名区分。

静态文件为什么也计费了。

检查是否开了 run_worker_first,或者文件路径没对上导致请求落到 Worker。前者是有意为之,后者通常是 directory 填错,实际没有上传任何文件。

Workers 的静态资源有文件数上限吗。

有,单文件 25 MiB 与 Pages 一致,文件数量上限比 Pages 免费档宽松,具体数值随套餐变化。文件多到几万的站点,把资源放 R2 更合适,配额与单文件上限见 56-free-tier-limits-cheatsheet.md。

小结

把静态文件交给 Workers,本质是把 Pages 的托管能力拆成两半:文件上传交给 assets,请求决策交给你写的 fetch。默认规则很省心,命中文件就不跑代码;需要干预时有两个开关,一个管找不到文件时怎么办,一个管哪些路径先过代码。

新项目的判断可以简化成一句:要"推仓库就上线"用 Pages,要"每个请求我说了算"用 Workers。两边都不缺静态托管能力,差的是工作流。

数据来源与检索时间

检索时间 2026-11-10。

来源URL对应数据
Workers Static Assetshttps://developers.cloudflare.com/workers/static-assets/assets.directory / binding 配置、请求命中的三条默认规则、env.ASSETS.fetch 用法、not_found_handling 取值
Pages Limitshttps://developers.cloudflare.com/pages/platform/limits/单文件 25 MiB,超大文件建议用 R2 公共桶
Pages Functions Routinghttps://developers.cloudflare.com/pages/functions/routing/_routes.json 控制调用范围,与 run_worker_first 对照

核验说明

  • 文档部分:配置字段、三条路由规则、not_found_handling 的三个取值、ASSETS 绑定的用法,均来自 2026-11-10 抓取的 Workers Static Assets 页面原文。
  • 未执行:本机 Token 只有 Workers 写权限,没有部署过带 assets 的 Worker,示例配置未实际下发生效。run_worker_first 的数组写法依据文档结构,未验证。
  • 未核实:正文提到"Pages 定位转向存量项目维护",依据是官方文档侧栏出现"Migrate to Workers"入口这一观察,未逐字引用官方的生命周期表述。
  • 未核实:Workers 静态资源的文件数上限具体数值随套餐变化,正文没有给数字。
  • 本地构建验证:无。