部署與配置完全指南)
Cloudflare Workers 靜態資源Static Assets部署與配置完全指南【免費下載鏈接】skillsSkills Catalog for Codex項目地址: https://gitcode.com/GitHub_Trending/skills4/skillsCloudflare Workers Static Assetsassets配置 ASSETS綁定是 Cloudflare 在 Workers 上托管靜態資源的官方能力適用于 SPAReact/Vue/Angular、SSG 站點以及靜態與動態 API 混合的全棧應用。讀完本文你將掌握如何在wrangler.jsonc中聲明靜態資源目錄與路由策略、如何通過ASSETS綁定在 Worker 代碼中接管請求、SPA/API/鑒權等高頻模式如何落地以及常見坑與性能優化手段。為什么選擇 Workers Static Assets 而不是 PagesCloudflare 提供兩套靜態托管方案官方參考文檔給出了如下對照維度Workers Static AssetsCloudflare Pages適用場景混合應用靜態資源 動態 API純靜態站點、SSGWorker 控制力對路由有完全控制權有限依賴 Functions配置方式代碼優先、靈活wrangler.jsoncGit 驅動、約定優先動態路由Worker-first 模式Functions_functions/目錄最適合全棧應用、帶 API 的 SPAJamstack、靜態文檔站決策樹需要自定義路由邏輯→ 選 Workers Static Assets純靜態站點或 SSG→ 選 PagesAPI 路由 SPA→ 選 Workers Static Assets使用框架Next、Nuxt、Remix→ 選 Pages簡單來說Workers Static Assets 把靜態文件變成了 Worker 生態里一個可編程的綁定適合需要深度定制請求處理的場景Pages 則把整個部署流程交給 Git 工作流適合開箱即用。快速開始最小可運行配置創建項目后只需在wrangler.jsonc中聲明assets.directory并把 Worker 的fetch處理器直接轉發給ASSETS綁定// wrangler.jsonc { name: my-app, main: src/index.ts, compatibility_date: 2025-01-01, assets: { directory: ./dist } }// src/index.ts export default { async fetch(request: Request, env: Env): PromiseResponse { return env.ASSETS.fetch(request); } };部署命令只需一條wrangler deploy其中env.ASSETS就是靜態資源綁定Fetcher接口的fetch方法接收并轉發任意請求。完整配置說明見 configuration.mdAPI 細節見 api.md。完整配置項詳解基礎配置最小配置只需要assets.directory一項{ name: my-worker, compatibility_date: 2025-01-01, // 新項目建議使用當前日期 assets: { directory: ./dist } }全部配置鍵{ name: my-worker, main: src/index.ts, compatibility_date: 2025-01-01, assets: { directory: ./dist, binding: ASSETS, not_found_handling: single-page-application, html_handling: auto-trailing-slash, run_worker_first: [/api/*, !/api/docs/*] } }各配置鍵說明鍵類型必填說明directorystring?靜態資源目錄路徑如./dist、./public、./buildbindingstring?Worker 代碼中訪問資源的綁定名如env.ASSETS默認ASSETSnot_found_handlingstring?資源未找到時的行為見下表html_handlingstring?HTML 文件 URL 尾斜杠行為run_worker_firstboolean | string[]?先調用 Worker 再檢查資源的路徑規則Wrangler 官方配置參考中還特別指出assets配置已取代舊版site配置成為 Workers 靜態文件的推薦方式見 wrangler/configuration.md。not_found_handling 模式控制資源不存在時的兜底行為模式行為適用場景single-page-application對非資源請求返回/index.htmlReact、Vue、Angular 等 SPA404-page存在則返回/404.html否則返回 404帶自定義錯誤頁的靜態站點none對缺失資源直接返回 404API-first 或自定義路由html_handling 模式控制 HTML 文件的尾斜杠行為模式/page/page/適用場景auto-trailing-slash若存在/page/index.html則重定向到/page/直接返回/page/index.html默認值SEO 友好force-trailing-slash總是重定向到/page/存在則直接返回統一尾斜杠風格drop-trailing-slash存在則直接返回重定向到/page更干凈的 URLnone不做任何修改不做任何修改自定義路由邏輯默認值auto-trailing-slashrun_worker_first 配置控制哪些請求先進入 Worker 再檢查靜態資源這是混合應用的核心開關。布爾語法所有請求都先走 Worker{ assets: { run_worker_first: true // 所有請求都調用 Worker } }數組語法推薦{ assets: { run_worker_first: [ /api/*, // 正向模式匹配 API 路由 /admin/*, // 匹配管理后臺路由 !/admin/assets/* // 負向模式排除管理后臺靜態資源 ] } }模式規則Glob 模式*任意字符、**任意路徑段負向模式以!前綴排除優先級負向模式覆蓋正向模式默認值false靜態資源直接由邊緣網絡響應不經過 Worker選擇建議API-first 應用靜態資源少→ 用true混合應用API 靜態資源→ 用數組模式靜態優先站點動態路由極少→ 用false.assetsignore 文件使用與.gitignore相同語法的.assetsignore文件可以排除無需上傳的文件# .assetsignore _worker.js *.map *.md node_modules/ .git/常見排除項_worker.js- 排除 Worker 代碼混入資源*.map- 排除 source map*.md- 排除 markdown 文件各類開發期產物Vite 插件集成Vite 項目可使用cloudflare/vite-plugin// vite.config.ts import { defineConfig } from vite; import { cloudflare } from cloudflare/vite-plugin; export default defineConfig({ plugins: [ cloudflare({ assets: { directory: ./dist, binding: ASSETS } }) ] });特性開發期間自動檢測資源資源熱更新HMR生產構建集成要求Wrangler 4.0.0、cloudflare/vite-plugin1.0.0關鍵兼容性日期日期特性影響2025-04-01導航請求優化SPA 導航請求跳過 Worker 調用降低成本新項目建議使用當前日期作為compatibility_date。多環境配置通過wrangler.jsonc的env字段為不同環境定制資源策略{ name: my-worker, assets: { directory: ./dist }, env: { staging: { assets: { not_found_handling: 404-page } }, production: { assets: { not_found_handling: single-page-application } } } }部署到指定環境wrangler deploy --env stagingASSETS 綁定 API 詳解類型定義ASSETS綁定通過Fetcher接口提供靜態資源訪問interface Env { ASSETS: Fetcher; } interface Fetcher { fetch(input: RequestInfo | URL, init?: RequestInit): PromiseResponse; }四種調用方式// 1. 轉發整個請求 await env.ASSETS.fetch(request); // 2. 字符串路徑主機名被忽略只有路徑有效 await env.ASSETS.fetch(https://any-host/path/to/asset.png); // 3. URL 對象 await env.ASSETS.fetch(new URL(/index.html, request.url)); // 4. 構造 Request 對象 await env.ASSETS.fetch(new Request(new URL(/logo.png, request.url), { method: GET, headers: request.headers }));關鍵行為字符串/URL 輸入的主機名host/origin會被忽略只使用路徑方法必須是 GET其他方法返回 405請求頭會透傳影響響應返回標準Response對象路徑解析資源相對于配置的assets.directory解析。以下調用會命中同一個資源env.ASSETS.fetch(https://example.com/logo.png) env.ASSETS.fetch(https://ignored.host/logo.png) env.ASSETS.fetch(/logo.png)影響響應的請求頭請求頭作用Accept-Encoding控制壓縮算法gzip、brotliRange支持部分內容206 響應If-None-Match基于 ETag 的條件請求If-Modified-Since基于修改日期的條件請求自定義請求頭會透傳但不影響資源服務。方法支持方法支持響應GET?資源內容HEAD?僅響應頭無響應體POST、PUT等?405 Method Not Allowed響應行為Content-Type、緩存與壓縮Content-Type 自動推斷根據文件擴展名自動設置擴展名Content-Type.htmltext/html; charsetutf-8.csstext/css.jsapplication/javascript.jsonapplication/json.pngimage/png.jpg、.jpegimage/jpeg.svgimage/svgxml.woff2font/woff2默認響應頭Content-Type: inferred ETag: hash Cache-Control: public, max-age3600 Content-Encoding: br (如果支持且收益明顯)Cache-Control 默認值大多數資源為 1 小時max-age3600可通過 Worker 響應變換覆蓋見下文模式 4。自動壓縮基于Accept-Encoding自動選擇Brotlibr首選壓縮率最高Gzipgzip兜底方案不壓縮客戶端不支持或資源過小無收益ETag 生成ETag 是基于內容的哈希用于條件請求If-None-Match。內容匹配時返回304 Not ModifiedETag: a3b2c1d4e5f6...錯誤響應與處理狀態碼觸發條件行為404資源未找到響應體取決于not_found_handling配置405非 GET/HEAD 方法{ error: Method not allowed }416Range 頭無效Range 無法滿足404 處理邏輯取決于配置// not_found_handling: single-page-application // 返回 /index.html狀態碼 200 // not_found_handling: 404-page // 存在則返回 /404.html否則返回 404 響應 // not_found_handling: none // 直接返回 404 響應修改響應const response await env.ASSETS.fetch(request); // 克隆并修改 return new Response(response.body, { status: response.status, headers: { ...Object.fromEntries(response.headers), Cache-Control: public, max-age31536000, X-Custom: value } });錯誤處理const response await env.ASSETS.fetch(request); if (!response.ok) { // 資源未找到或出錯 return new Response(Custom error page, { status: 404 }); } return response;條件服務const url new URL(request.url); // 根據條件提供不同資源 if (url.pathname /) { return env.ASSETS.fetch(/index.html); } return env.ASSETS.fetch(request);高頻實戰模式以下模式均來自 patterns.md可直接復制使用。1. 轉發請求到資源export default { async fetch(request: Request, env: Env): PromiseResponse { return env.ASSETS.fetch(request); } };2. 按路徑獲取指定資源const response await env.ASSETS.fetch(https://assets.local/logo.png);3. 修改請求后再取資源const url new URL(request.url); url.pathname /index.html; return env.ASSETS.fetch(new Request(url, request));4. 變換資源響應追加自定義頭 / 覆蓋緩存const response await env.ASSETS.fetch(request); const modifiedResponse new Response(response.body, response); modifiedResponse.headers.set(X-Custom-Header, value); modifiedResponse.headers.set(Cache-Control, public, max-age3600); return modifiedResponse;5. 條件資源服務export default { async fetch(request: Request, env: Env): PromiseResponse { const url new URL(request.url); if (url.pathname /) { return env.ASSETS.fetch(/index.html); } return env.ASSETS.fetch(request); } };6. SPA API 路由最常用的全棧模式靜態 SPA 與后端 API 共存export default { async fetch(request: Request, env: Env): PromiseResponse { const url new URL(request.url); if (url.pathname.startsWith(/api/)) { return handleAPI(request, env); } return env.ASSETS.fetch(request); } }; async function handleAPI(request: Request, env: Env): PromiseResponse { return new Response(JSON.stringify({ status: ok }), { headers: { Content-Type: application/json } }); }配套配置設置run_worker_first: [/api/*]讓 API 請求先進入 Worker 邏輯。7. 受保護資源的鑒權攔截export default { async fetch(request: Request, env: Env): PromiseResponse { const url new URL(request.url); if (url.pathname.startsWith(/admin/)) { const session await validateSession(request, env); if (!session) { return Response.redirect(/login, 302); } } return env.ASSETS.fetch(request); } };配套配置run_worker_first: [/admin/*]8. 安全響應頭export default { async fetch(request: Request, env: Env): PromiseResponse { const response await env.ASSETS.fetch(request); const secureResponse new Response(response.body, response); secureResponse.headers.set(X-Frame-Options, DENY); secureResponse.headers.set(X-Content-Type-Options, nosniff); secureResponse.headers.set(Content-Security-Policy, default-src self); return secureResponse; } };9. 基于 Cookie 的 A/B 測試export default { async fetch(request: Request, env: Env): PromiseResponse { const cookies request.headers.get(Cookie) || ; const variant cookies.includes(variantb) ? b : a; const url new URL(request.url); if (url.pathname /) { return env.ASSETS.fetch(/index-${variant}.html); } return env.ASSETS.fetch(request); } };10. 基于語言的本地化路由export default { async fetch(request: Request, env: Env): PromiseResponse { const locale request.headers.get(Accept-Language)?.split(,)[0] || en; const url new URL(request.url); if (url.pathname /) { return env.ASSETS.fetch(/${locale}/index.html); } if (!url.pathname.startsWith(/${locale}/)) { url.pathname /${locale}${url.pathname}; } return env.ASSETS.fetch(url); } };11. OAuth 回調處理export default { async fetch(request: Request, env: Env): PromiseResponse { const url new URL(request.url); if (url.pathname /auth/callback) { const code url.searchParams.get(code); if (code) { const session await exchangeCode(code, env); return new Response(null, { status: 302, headers: { Location: /, Set-Cookie: session${session}; HttpOnly; Secure; SameSiteLax } }); } } return env.ASSETS.fetch(request); } };配套配置run_worker_first: [/auth/*]12. 緩存控制覆蓋內容哈希文件名export default { async fetch(request: Request, env: Env): PromiseResponse { const response await env.ASSETS.fetch(request); const url new URL(request.url); // 不可變資源帶哈希文件名 if (/\.[a-f0-9]{8,}\.(js|css|png|jpg)$/.test(url.pathname)) { return new Response(response.body, { ...response, headers: { ...Object.fromEntries(response.headers), Cache-Control: public, max-age31536000, immutable } }); } return response; } };最佳實踐1. 使用選擇性 Worker-First 路由不要用run_worker_first true改用數組模式{ assets: { run_worker_first: [ /api/*, // API 路由 /admin/*, // 管理后臺 !/admin/assets/* // 排除后臺靜態資源 ] } }收益減少 Worker 調用次數、降低成本、提升資源交付性能。2. 利用導航請求優化SPA 項目將compatibility_date設為2025-04-01或更新{ compatibility_date: 2025-04-01, assets: { not_found_handling: single-page-application } }導航請求會跳過 Worker 調用降低成本。3. 綁定類型安全始終為環境聲明類型interface Env { ASSETS: Fetcher; }常見錯誤排查Asset not found原因資源不在資源目錄、路徑錯誤、資源未部署解決確認資源存在、檢查路徑大小寫、必要時重新部署Worker not invoked for asset原因資源被直接提供run_worker_first未配置解決配置run_worker_first模式以覆蓋對應路由見 configuration.md429 Too Many Requests on free tier原因run_worker_first模式讓大量請求進入 Worker觸達免費版限制10 萬次/天解決使用更精細的模式含負向排除或升級付費計劃Smart Placement increases latency原因run_worker_firsttrue Smart Placement 將所有請求路由到單個智能放置點解決使用數組語法做選擇性匹配或對資源密集型應用關閉 Smart PlacementCF-Cache-Status header unreliable原因出于隱私原因該頭是概率性添加的解決關鍵路由邏輯不要依賴CF-Cache-Status改用 ETag、age 等其他信號JWT expired during deployment原因大型資源部署超過 JWT token 有效期解決升級到 Wrangler 4.34.0自動刷新 token或減少資源數量Cannot use assets with site原因舊版site配置與新版assets配置沖突解決從site遷移到assets見 configuration.md并從wrangler.jsonc中移除site鍵Assets not updating after deployment原因瀏覽器或 CDN 緩存提供了舊資源解決強制刷新瀏覽器CmdShiftR / CtrlF5使用緩存破壞手段哈希文件名用wrangler tail確認部署已完成平臺限制資源/限制免費版付費版備注單文件最大體積25 MiB25 MiB按文件計資源總數20,000100,000需要 Wrangler 4.34.02025 年 9 月Worker 調用次數10 萬/天1000 萬/月用run_worker_first模式優化資源存儲無限無限已包含版本要求特性最低 Wrangler 版本10 萬文件上限付費4.34.0Vite 插件4.0.0 cloudflare/vite-plugin 1.0.0導航優化4.0.0 compatibility_date: 2025-04-01性能優化技巧1. 使用哈希文件名用內容哈希文件名開啟長期緩存app.a3b2c1d4.js styles.e5f6g7h8.css大多數打包器Vite、Webpack、Parcel會自動生成。2. 最小化 Worker 調用盡量讓資源直接被邊緣服務{ assets: { // 只為動態路由調用 Worker run_worker_first: [/api/*, /auth/*] } }3. 充分利用瀏覽器緩存為不同資源設置合適的Cache-Control// 帶版本號的資源 Cache-Control: public, max-age31536000, immutable // HTML經常校驗 Cache-Control: public, max-age0, must-revalidate4. 使用 .assetsignore排除非必要文件以縮短上傳時間*.map *.md .DS_Store node_modules/部署前的準備工作從 SKILL.md 可知部署前需確認認證狀態靜態資源部署同樣適用npx wrangler whoami # 確認已登錄的賬戶本地開發交互式登錄使用wrangler login一次性 OAuthCI/CD 環境設置CLOUDFLARE_API_TOKEN環境變量詳見 wrangler/auth.md。延伸閱讀本倉庫中與該主題相關的參考資料configuration.md - 完整配置、路由模式、兼容性日期api.md - ASSETS 綁定 API、請求/響應處理patterns.md - 常見模式SPA、API 路由、鑒權、A/B 測試等gotchas.md - 限制、錯誤、性能建議wrangler/configuration.md - Wrangler 全局配置、環境與綁定參考【免費下載鏈接】skillsSkills Catalog for Codex項目地址: https://gitcode.com/GitHub_Trending/skills4/skills創作聲明:本文部分內容由AI輔助生成(AIGC),僅供參考