Cloudflare Worker部署React子路径应用静态资源404/500问题
该问题是React SPA以子路径模式部署到Cloudflare Workers Sites时的典型路径匹配错误,核心诱因如下:
- 默认的
serveSinglePageApp工具函数不会自动剥离路由规则匹配到的/vendor前缀:Worker收到/vendor/static/xxx.js类请求时,会直接在KV存储中查找vendor/static/xxx.js路径的文件,但CRA构建产出的静态资源直接存放在static/目录下,不存在vendor这层父目录,匹配失败直接返回404。 - React Router未配置子路径基准值:
BrowserRouter默认以站点根路径/作为路由匹配基准,子路径部署时路由跳转、资源引用逻辑都会出现偏移。 - 配置与构建基准路径不匹配:wrangler.toml内残留的错误域名会导致路由规则完全失效,若package.json的homepage字段配置错误,构建出的index.html中的资源引用路径也会出错。
1. 修正wrangler.toml基础配置
首先修正域名笔误,替换所有占位假值为Cloudflare后台对应的真实ID,最终配置参考如下:
name = "vendorapp" type = "webpack" account_id = "你的Cloudflare账户真实ID" route = "https://healthify.com/vendor/*" zone_id = "你的域名对应真实zone_id" [site] bucket = "./build" entry-point = "workers-site"
注意:配置修改后暂不发布,后续调整完所有逻辑后统一执行部署
2. 确认package.json构建基准路径
打开项目根目录的package.json,确认homepage字段值与部署地址完全匹配:
{ "homepage": "https://healthify.com/vendor" }
字段配置完成后,在项目根目录重新执行构建命令生成最新产物:
npm run build
该配置会让CRA在构建时自动给index.html中引用的所有静态资源加上/vendor/前缀,避免资源路径引用错误。
3. 自定义Worker资源映射逻辑
默认的serveSinglePageApp不支持子路径部署的前缀剥离,需要自定义请求转换逻辑:先剥离请求路径中的/vendor前缀,再执行KV资源匹配,同时保留SPA单页应用的回退规则(非静态文件请求统一返回index.html)。
将workers-site/index.js的代码替换为如下内容:
import { getAssetFromKV } from '@cloudflare/kv-asset-handler'; addEventListener("fetch", event => { event.respondWith(handleEvent(event)); }); async function handleEvent(event) { const request = event.request; const url = new URL(request.url); // 自定义资源映射规则,适配子路径部署 const mapRequestToAsset = (req) => { const reqUrl = new URL(req.url); let pathname = reqUrl.pathname; // 剥离路径开头的/vendor前缀 pathname = pathname.replace(/^\/vendor/, '') || '/'; // 复用SPA回退逻辑:无文件后缀的路径统一返回index.html if (!pathname.includes('.')) { pathname = '/index.html'; } reqUrl.pathname = pathname; return new Request(reqUrl.toString(), req); }; try { return await getAssetFromKV(event, { mapRequestToAsset }); } catch (error) { return new Response("Resource not found", { status: 404, statusText: "not found" }); } }
4. 给React Router配置子路径基准
修改App.js中的BrowserRouter标签,添加basename属性声明应用部署的子路径,保证前端路由匹配正确:
<BrowserRouter basename="/vendor"> <Routes> <Route path="/" element={<AccountSetupSuccessfull />} /> <Route path="/verify-phone" element={<VerifyPhone />} /> <Route path="/enter-gstin" element={<EnterGSTIN />} /> <Route path="/company-location" element={<CompanyLocation />} /> <Route path="/account-setup-successful" element={<AccountSetupSuccessfull />} /> </Routes> </BrowserRouter>
注意:配置basename后,Route的path参数不需要再加/vendor前缀,比如/verify-phone会自动匹配https://healthify.com/vendor/verify-phone地址
5. 重新部署验证
所有配置修改完成后,执行部署命令发布Worker:
wrangler publish
发布后先直接访问静态资源地址(比如https://healthify.com/vendor/static/css/main.xxx.css)确认返回200,再访问各前端子路由验证功能正常。
如果部署后仍出现500错误,按以下顺序排查:
- 确认发布前已经重新执行
npm run build,最新构建产物已经同步上传到KV存储 - 检查Worker的KV命名空间绑定状态,发布日志中无KV权限类报错
- 检查本地build目录结构,确认static目录直接位于build根目录下,不存在嵌套的vendor文件夹
- 部署验证阶段可临时开启Cloudflare开发模式,绕过缓存规则避免旧资源干扰
内容的提问来源于stack exchange,提问作者xanders Doing

