[{"data":1,"prerenderedAt":914},["ShallowReactive",2],{"page-\u002Farchitecture\u002Fcloudflare-workers":3},{"id":4,"title":5,"body":6,"description":12,"extension":903,"meta":904,"navigation":196,"path":910,"seo":911,"stem":912,"__hash__":913},"content\u002Farchitecture\u002FCloudflare Workers.md","Cloudflare Workers",{"type":7,"value":8,"toc":898},"minimark",[9,13,16,19,22,26,38,46,322,329,333,343,346,384,403,418,424,427,434,505,508,559,825,828,844,847,850,853,856,859,863,866,885,888,891,894],[10,11,12],"p",{},"Cloudflare Workers 是一种将 JavaScript\u002FTypeScript 代码直接部署到 Cloudflare 全球边缘网络运行的无服务器（Serverless）计算平台。它的核心优势在于极低的延迟、近乎为零的冷启动时间，以及为全栈应用提供的一整套边缘原生生态。",[10,14,15],{},"理解 Workers 的关键在于它的执行模型，它与传统的基于容器的 Serverless（如 AWS Lambda）有本质不同。",[10,17,18],{},"workers没有使用虚拟机或者容器，而是利用了chrome和nodejs同款的v8引擎中的isolate技术，可以理解为极其轻量的js沙箱，多个isolate可以共享同一个运行时进程，内存完全隔离。由于不需要启动完整的操作系统和运行时，因此一个isolate的启动速度比传统容器快了约100倍，通常是5ms，用户是几乎感觉不到的，这个使得worker非常适合处理延迟敏感的API请求。",[10,20,21],{},"代码会运行在cloudflare遍布全球的300多个城市节点上，请求会被自动路由到最近的节点处理，它的计费基于请求数和CPU计算时间，而不是空闲的资源占用。",[23,24,25],"h2",{"id":25},"作为中间层处理请求",[10,27,28,29,33,34,37],{},"之前遇到的 ",[30,31,32],"code",{},"dog.ceo"," 图片请求来做例子。浏览器直接 ",[30,35,36],{},"fetch"," 第三方 API 会被 CORS 策略拦截，因为目标服务器没有返回允许跨域的响应头。",[10,39,40,41,45],{},"Workers 作为一个中间层，可以完美解决这个问题。它的逻辑很简单：",[42,43,44],"strong",{},"让浏览器请求你的 Worker（同源），由 Worker 在服务端（不受 CORS 限制）去请求目标 API，并在返回给浏览器的响应中手动加上 CORS 头","。",[47,48,53],"pre",{"className":49,"code":50,"language":51,"meta":52,"style":52},"language-ts shiki shiki-themes github-light github-dark","export default {\n  async fetch(request) {\n    \u002F\u002F 1. 从请求的 URL 中提取真正的目标地址\n    const url = new URL(request.url);\n    const targetUrl = url.searchParams.get(\"url\");\n    if (!targetUrl) {\n      return new Response(\"Missing 'url' parameter\", { status: 400 });\n    }\n\n    \u002F\u002F 2. 在服务端发起对目标地址的请求（此处没有 CORS 限制）\n    const response = await fetch(targetUrl);\n\n    \u002F\u002F 3. 复制响应，并注入 CORS 头，允许任何来源访问\n    const newHeaders = new Headers(response.headers);\n    newHeaders.set(\"Access-Control-Allow-Origin\", \"*\");\n    \n    return new Response(response.body, {\n      status: response.status,\n      headers: newHeaders,\n    });\n  },\n};\n","ts","",[30,54,55,71,91,98,120,145,160,185,191,198,204,222,227,233,251,273,279,292,298,304,310,316],{"__ignoreMap":52},[56,57,60,64,67],"span",{"class":58,"line":59},"line",1,[56,61,63],{"class":62},"szBVR","export",[56,65,66],{"class":62}," default",[56,68,70],{"class":69},"sVt8B"," {\n",[56,72,74,77,81,84,88],{"class":58,"line":73},2,[56,75,76],{"class":62},"  async",[56,78,80],{"class":79},"sScJk"," fetch",[56,82,83],{"class":69},"(",[56,85,87],{"class":86},"s4XuR","request",[56,89,90],{"class":69},") {\n",[56,92,94],{"class":58,"line":93},3,[56,95,97],{"class":96},"sJ8bj","    \u002F\u002F 1. 从请求的 URL 中提取真正的目标地址\n",[56,99,101,104,108,111,114,117],{"class":58,"line":100},4,[56,102,103],{"class":62},"    const",[56,105,107],{"class":106},"sj4cs"," url",[56,109,110],{"class":62}," =",[56,112,113],{"class":62}," new",[56,115,116],{"class":79}," URL",[56,118,119],{"class":69},"(request.url);\n",[56,121,123,125,128,130,133,136,138,142],{"class":58,"line":122},5,[56,124,103],{"class":62},[56,126,127],{"class":106}," targetUrl",[56,129,110],{"class":62},[56,131,132],{"class":69}," url.searchParams.",[56,134,135],{"class":79},"get",[56,137,83],{"class":69},[56,139,141],{"class":140},"sZZnC","\"url\"",[56,143,144],{"class":69},");\n",[56,146,148,151,154,157],{"class":58,"line":147},6,[56,149,150],{"class":62},"    if",[56,152,153],{"class":69}," (",[56,155,156],{"class":62},"!",[56,158,159],{"class":69},"targetUrl) {\n",[56,161,163,166,168,171,173,176,179,182],{"class":58,"line":162},7,[56,164,165],{"class":62},"      return",[56,167,113],{"class":62},[56,169,170],{"class":79}," Response",[56,172,83],{"class":69},[56,174,175],{"class":140},"\"Missing 'url' parameter\"",[56,177,178],{"class":69},", { status: ",[56,180,181],{"class":106},"400",[56,183,184],{"class":69}," });\n",[56,186,188],{"class":58,"line":187},8,[56,189,190],{"class":69},"    }\n",[56,192,194],{"class":58,"line":193},9,[56,195,197],{"emptyLinePlaceholder":196},true,"\n",[56,199,201],{"class":58,"line":200},10,[56,202,203],{"class":96},"    \u002F\u002F 2. 在服务端发起对目标地址的请求（此处没有 CORS 限制）\n",[56,205,207,209,212,214,217,219],{"class":58,"line":206},11,[56,208,103],{"class":62},[56,210,211],{"class":106}," response",[56,213,110],{"class":62},[56,215,216],{"class":62}," await",[56,218,80],{"class":79},[56,220,221],{"class":69},"(targetUrl);\n",[56,223,225],{"class":58,"line":224},12,[56,226,197],{"emptyLinePlaceholder":196},[56,228,230],{"class":58,"line":229},13,[56,231,232],{"class":96},"    \u002F\u002F 3. 复制响应，并注入 CORS 头，允许任何来源访问\n",[56,234,236,238,241,243,245,248],{"class":58,"line":235},14,[56,237,103],{"class":62},[56,239,240],{"class":106}," newHeaders",[56,242,110],{"class":62},[56,244,113],{"class":62},[56,246,247],{"class":79}," Headers",[56,249,250],{"class":69},"(response.headers);\n",[56,252,254,257,260,262,265,268,271],{"class":58,"line":253},15,[56,255,256],{"class":69},"    newHeaders.",[56,258,259],{"class":79},"set",[56,261,83],{"class":69},[56,263,264],{"class":140},"\"Access-Control-Allow-Origin\"",[56,266,267],{"class":69},", ",[56,269,270],{"class":140},"\"*\"",[56,272,144],{"class":69},[56,274,276],{"class":58,"line":275},16,[56,277,278],{"class":69},"    \n",[56,280,282,285,287,289],{"class":58,"line":281},17,[56,283,284],{"class":62},"    return",[56,286,113],{"class":62},[56,288,170],{"class":79},[56,290,291],{"class":69},"(response.body, {\n",[56,293,295],{"class":58,"line":294},18,[56,296,297],{"class":69},"      status: response.status,\n",[56,299,301],{"class":58,"line":300},19,[56,302,303],{"class":69},"      headers: newHeaders,\n",[56,305,307],{"class":58,"line":306},20,[56,308,309],{"class":69},"    });\n",[56,311,313],{"class":58,"line":312},21,[56,314,315],{"class":69},"  },\n",[56,317,319],{"class":58,"line":318},22,[56,320,321],{"class":69},"};\n",[10,323,324,325,328],{},"部署后，前端只需请求 ",[30,326,327],{},"https:\u002F\u002F你的worker.workers.dev\u002F?url=https:\u002F\u002Fdog.ceo\u002Fapi\u002Fbreeds\u002Fimage\u002Frandom"," 即可获取数据，浏览器不会再报 CORS 错误。",[23,330,332],{"id":331},"bindings","Bindings",[10,334,335,336,338,339,342],{},"Workers 本身是无状态的，它通过 ",[42,337,332],{}," 这一机制来连接各种外部资源，这是构建全栈应用的基础。你不需要在代码里管理数据库密码或连接字符串，只需在配置中声明绑定，运行时通过 ",[30,340,341],{},"env"," 对象访问即可。",[10,344,345],{},"常见的绑定包括：",[347,348,349,356,362,372,378],"ul",{},[350,351,352,355],"li",{},[42,353,354],{},"KV","：低延迟的键值存储，适合存储会话、配置或缓存。",[350,357,358,361],{},[42,359,360],{},"D1","：基于 SQLite 的边缘关系型数据库，支持标准的 SQL 查询。",[350,363,364,367,368,371],{},[42,365,366],{},"R2","：与 S3 兼容的对象存储，且",[42,369,370],{},"没有出口流量费用","，适合存放图片、文件等静态资源。",[350,373,374,377],{},[42,375,376],{},"Service Bindings","：允许一个 Worker 直接调用另一个 Worker，用于构建微服务架构。",[350,379,380,383],{},[42,381,382],{},"Durable Objects","：提供强一致性的有状态协调能力，适合实现实时协作、聊天室等场景。",[10,385,386,387,390,391,394,395,398,399,402],{},"我们之前熟悉 ",[42,388,389],{},"Nitro"," 微后端开发，它可以直接构建并部署到 Cloudflare Workers。你几乎不需要重写业务逻辑，只需在 ",[30,392,393],{},"nitro.config.ts"," 中指定 ",[30,396,397],{},"preset: \"cloudflare_module\"","，Nitro 就会将你的代码打包成 Workers 可运行的格式。之后使用 ",[30,400,401],{},"wrangler deploy"," 即可发布。",[10,404,405,406,409,410,413,414,417],{},"在 Workers 生态中，",[42,407,408],{},"Hono"," 是一个备受推崇的轻量级 Web 框架，它的 API 设计对熟悉 Express 的开发者非常友好，且完全基于 Web 标准（",[30,411,412],{},"Request","\u002F",[30,415,416],{},"Response","）构建。你可以把它看作是 Workers 环境下的“Express”，是构建 API 和代理服务的高效选择。",[419,420,421],"blockquote",{},[10,422,423],{},"浏览器web worker是我们用来执行用户js代码、防止主线程卡死的方案，运行在用户的浏览器里，是前端页面的一部分。但是cloudflare workers是部署服务端代码的地方，运行在边缘网络上，是一个独立的serverless运行环境。",[10,425,426],{},"cloudflare workers和nodejs最大区别在于workers运行时基于web标准，也就是Request、Response、fetch构建，但是nodejs有自己的标准库fs http net，为了让你能在workers上使用nodejs api的npm包，cloudflare提供了的nodejs_compat兼容性标志，对于兼容性在2026-08-04或者之后的worker，这个标志是默认开启的。",[10,428,429,430,433],{},"尽管兼容性很好，但有些 Node.js 的能力在 Workers 的 Serverless 模型中",[42,431,432],{},"无法支持","，或者在实现上有本质区别：",[347,435,436,454,460,483],{},[350,437,438,445,446,449,450,453],{},[42,439,440,441,444],{},"文件系统 (",[30,442,443],{},"fs",") 是“虚拟”的","：Workers 没有传统的本地磁盘。",[30,447,448],{},"node:fs"," 模块虽然可用，但它操作的是一个",[42,451,452],{},"基于内存的、每个 Worker 独立的虚拟文件系统","，用于处理临时文件，而非持久化存储。",[350,455,456,459],{},[42,457,458],{},"C++ 原生插件不支持","：依赖 Node-API 的 C++ Addons 无法在 Workers 中运行。",[350,461,462,465,466,469,470,469,473,469,476,469,479,482],{},[42,463,464],{},"部分模块完全不可用","：",[30,467,468],{},"Child Processes","、",[30,471,472],{},"Cluster",[30,474,475],{},"Readline",[30,477,478],{},"TTY",[30,480,481],{},"UDP\u002Fdatagram"," 等在 Serverless 上下文中没有意义的模块是不支持的。",[350,484,485,465,488,491,492,495,496,491,499,504],{},[42,486,487],{},"网络实现是封装而非原生",[30,489,490],{},"node:net"," 和 ",[30,493,494],{},"node:http"," 并非直接操作内核套接字，而是 Cloudflare 基于自己的 ",[42,497,498],{},"Sockets API",[42,500,501,503],{},[30,502,36],{}," API"," 封装实现的。这意味着其行为和底层机制与在 Node.js 中直接使用内核网络栈不同。",[10,506,507],{},"部署方面的话，wrangler目前支持两种格式，可以选一，你可以写wrangler.toml或者是wrangler.jsonc，后者是目前更推荐的新格式，可以更好地获得ide的语法提示和校验。",[47,509,513],{"className":510,"code":511,"language":512,"meta":52,"style":52},"language-toml shiki shiki-themes github-light github-dark","name = \"my-nitro-app\"\nmain = \".\u002F.output\u002Fserver\u002Findex.mjs\"\ncompatibility_date = \"2024-11-12\"\ncompatibility_flags = [\"nodejs_compat\"]\n\n# 指定静态资源目录，并绑定到 ASSETS 变量\n[assets]\ndirectory = \".\u002F.output\u002Fpublic\"\nbinding = \"ASSETS\"\n","toml",[30,514,515,520,525,530,535,539,544,549,554],{"__ignoreMap":52},[56,516,517],{"class":58,"line":59},[56,518,519],{},"name = \"my-nitro-app\"\n",[56,521,522],{"class":58,"line":73},[56,523,524],{},"main = \".\u002F.output\u002Fserver\u002Findex.mjs\"\n",[56,526,527],{"class":58,"line":93},[56,528,529],{},"compatibility_date = \"2024-11-12\"\n",[56,531,532],{"class":58,"line":100},[56,533,534],{},"compatibility_flags = [\"nodejs_compat\"]\n",[56,536,537],{"class":58,"line":122},[56,538,197],{"emptyLinePlaceholder":196},[56,540,541],{"class":58,"line":147},[56,542,543],{},"# 指定静态资源目录，并绑定到 ASSETS 变量\n",[56,545,546],{"class":58,"line":162},[56,547,548],{},"[assets]\n",[56,550,551],{"class":58,"line":187},[56,552,553],{},"directory = \".\u002F.output\u002Fpublic\"\n",[56,555,556],{"class":58,"line":193},[56,557,558],{},"binding = \"ASSETS\"\n",[47,560,564],{"className":561,"code":562,"language":563,"meta":52,"style":52},"language-json shiki shiki-themes github-light github-dark","\u002F\u002Fjsonc\n{\n  \u002F\u002F 启用 IDE 智能提示和校验（可选，但强烈推荐）\n  \"$schema\": \"node_modules\u002Fwrangler\u002Fconfig-schema.json\",\n\n  \u002F\u002F 【核心配置】\n  \"name\": \"my-nitro-app\",           \u002F\u002F Worker 项目名称\n  \"main\": \".output\u002Fserver\u002Findex.mjs\", \u002F\u002F 入口文件（Nitro 构建后的路径）\n  \n  \u002F\u002F 【兼容性设置】\n  \"compatibility_date\": \"2026-10-24\", \u002F\u002F 建议设置为当前日期\n  \"compatibility_flags\": [\"nodejs_compat\"], \u002F\u002F 开启 Node.js API 兼容\n\n  \u002F\u002F 【静态资源绑定】（Nitro\u002FNuxt 项目常用）\n  \"assets\": {\n    \"directory\": \".output\u002Fpublic\",  \u002F\u002F 静态资源目录\n    \"binding\": \"ASSETS\"            \u002F\u002F 在代码中通过 env.ASSETS 访问\n  },\n\n  \u002F\u002F 【环境变量】（非敏感信息）\n  \"vars\": {\n    \"API_ENDPOINT\": \"https:\u002F\u002Fapi.example.com\"\n  },\n\n  \u002F\u002F 【KV 命名空间绑定】（示例）\n  \"kv_namespaces\": [\n    {\n      \"binding\": \"MY_KV\",\n      \"id\": \"\u003CYOUR_KV_NAMESPACE_ID>\"\n    }\n  ]\n}\n","json",[30,565,566,571,576,581,595,599,604,620,635,640,645,660,677,681,686,694,710,723,727,731,736,743,753,758,763,769,778,784,797,808,813,819],{"__ignoreMap":52},[56,567,568],{"class":58,"line":59},[56,569,570],{"class":96},"\u002F\u002Fjsonc\n",[56,572,573],{"class":58,"line":73},[56,574,575],{"class":69},"{\n",[56,577,578],{"class":58,"line":93},[56,579,580],{"class":96},"  \u002F\u002F 启用 IDE 智能提示和校验（可选，但强烈推荐）\n",[56,582,583,586,589,592],{"class":58,"line":100},[56,584,585],{"class":106},"  \"$schema\"",[56,587,588],{"class":69},": ",[56,590,591],{"class":140},"\"node_modules\u002Fwrangler\u002Fconfig-schema.json\"",[56,593,594],{"class":69},",\n",[56,596,597],{"class":58,"line":122},[56,598,197],{"emptyLinePlaceholder":196},[56,600,601],{"class":58,"line":147},[56,602,603],{"class":96},"  \u002F\u002F 【核心配置】\n",[56,605,606,609,611,614,617],{"class":58,"line":162},[56,607,608],{"class":106},"  \"name\"",[56,610,588],{"class":69},[56,612,613],{"class":140},"\"my-nitro-app\"",[56,615,616],{"class":69},",           ",[56,618,619],{"class":96},"\u002F\u002F Worker 项目名称\n",[56,621,622,625,627,630,632],{"class":58,"line":187},[56,623,624],{"class":106},"  \"main\"",[56,626,588],{"class":69},[56,628,629],{"class":140},"\".output\u002Fserver\u002Findex.mjs\"",[56,631,267],{"class":69},[56,633,634],{"class":96},"\u002F\u002F 入口文件（Nitro 构建后的路径）\n",[56,636,637],{"class":58,"line":193},[56,638,639],{"class":69},"  \n",[56,641,642],{"class":58,"line":200},[56,643,644],{"class":96},"  \u002F\u002F 【兼容性设置】\n",[56,646,647,650,652,655,657],{"class":58,"line":206},[56,648,649],{"class":106},"  \"compatibility_date\"",[56,651,588],{"class":69},[56,653,654],{"class":140},"\"2026-10-24\"",[56,656,267],{"class":69},[56,658,659],{"class":96},"\u002F\u002F 建议设置为当前日期\n",[56,661,662,665,668,671,674],{"class":58,"line":224},[56,663,664],{"class":106},"  \"compatibility_flags\"",[56,666,667],{"class":69},": [",[56,669,670],{"class":140},"\"nodejs_compat\"",[56,672,673],{"class":69},"], ",[56,675,676],{"class":96},"\u002F\u002F 开启 Node.js API 兼容\n",[56,678,679],{"class":58,"line":229},[56,680,197],{"emptyLinePlaceholder":196},[56,682,683],{"class":58,"line":235},[56,684,685],{"class":96},"  \u002F\u002F 【静态资源绑定】（Nitro\u002FNuxt 项目常用）\n",[56,687,688,691],{"class":58,"line":253},[56,689,690],{"class":106},"  \"assets\"",[56,692,693],{"class":69},": {\n",[56,695,696,699,701,704,707],{"class":58,"line":275},[56,697,698],{"class":106},"    \"directory\"",[56,700,588],{"class":69},[56,702,703],{"class":140},"\".output\u002Fpublic\"",[56,705,706],{"class":69},",  ",[56,708,709],{"class":96},"\u002F\u002F 静态资源目录\n",[56,711,712,715,717,720],{"class":58,"line":281},[56,713,714],{"class":106},"    \"binding\"",[56,716,588],{"class":69},[56,718,719],{"class":140},"\"ASSETS\"",[56,721,722],{"class":96},"            \u002F\u002F 在代码中通过 env.ASSETS 访问\n",[56,724,725],{"class":58,"line":294},[56,726,315],{"class":69},[56,728,729],{"class":58,"line":300},[56,730,197],{"emptyLinePlaceholder":196},[56,732,733],{"class":58,"line":306},[56,734,735],{"class":96},"  \u002F\u002F 【环境变量】（非敏感信息）\n",[56,737,738,741],{"class":58,"line":312},[56,739,740],{"class":106},"  \"vars\"",[56,742,693],{"class":69},[56,744,745,748,750],{"class":58,"line":318},[56,746,747],{"class":106},"    \"API_ENDPOINT\"",[56,749,588],{"class":69},[56,751,752],{"class":140},"\"https:\u002F\u002Fapi.example.com\"\n",[56,754,756],{"class":58,"line":755},23,[56,757,315],{"class":69},[56,759,761],{"class":58,"line":760},24,[56,762,197],{"emptyLinePlaceholder":196},[56,764,766],{"class":58,"line":765},25,[56,767,768],{"class":96},"  \u002F\u002F 【KV 命名空间绑定】（示例）\n",[56,770,772,775],{"class":58,"line":771},26,[56,773,774],{"class":106},"  \"kv_namespaces\"",[56,776,777],{"class":69},": [\n",[56,779,781],{"class":58,"line":780},27,[56,782,783],{"class":69},"    {\n",[56,785,787,790,792,795],{"class":58,"line":786},28,[56,788,789],{"class":106},"      \"binding\"",[56,791,588],{"class":69},[56,793,794],{"class":140},"\"MY_KV\"",[56,796,594],{"class":69},[56,798,800,803,805],{"class":58,"line":799},29,[56,801,802],{"class":106},"      \"id\"",[56,804,588],{"class":69},[56,806,807],{"class":140},"\"\u003CYOUR_KV_NAMESPACE_ID>\"\n",[56,809,811],{"class":58,"line":810},30,[56,812,190],{"class":69},[56,814,816],{"class":58,"line":815},31,[56,817,818],{"class":69},"  ]\n",[56,820,822],{"class":58,"line":821},32,[56,823,824],{"class":69},"}\n",[10,826,827],{},"当终端执行了wrangler login登录了之后，就会启动一个标准的oauth2.0流程，授权了wranler代理之后本地就会保存凭证，之后在同一台机器部署的时候就不需要登录了。",[10,829,830,831,834,835,840,841,45],{},"Nuxt 在默认执行 ",[30,832,833],{},"nuxt build","（Node 预设）后，Nitro 构建出的服务端入口文件名称是 ",[42,836,837],{},[30,838,839],{},"index.mjs","，完整路径位于项目根目录的 ",[30,842,843],{},".output\u002Fserver\u002Findex.mjs",[10,845,846],{},"Free Plan:",[10,848,849],{},"适合个人项目、学习或低流量场景，每月成本 $0。",[10,851,852],{},"请求数：每天 100,000 次（涵盖所有 Worker 脚本，UTC 0点重置）。",[10,854,855],{},"CPU 时间：每次请求 10 毫秒。注意，这只是 CPU 计算时间，等待网络请求（如 fetch）的时间不计算在内。",[10,857,858],{},"其他限制：最多 100 个 Worker 脚本，每天 200,000 条日志。",[23,860,862],{"id":861},"serverless","Serverless",[10,864,865],{},"通常，Serverless 包含两个层面：",[867,868,869,879],"ol",{},[350,870,871,874,875,878],{},[42,872,873],{},"FaaS (Function as a Service，函数即服务)","：这是 Serverless 的核心。你只写一个个独立的函数，只有当请求来的时候，平台才会启动一个实例来执行你的函数，执行完立刻销毁。",[42,876,877],{},"按运行时间或请求次数计费","（没请求时完全不花钱）。比如AWS Lambda、阿里云函数计算（FC）、腾讯云云函数（SCF）、Google Cloud Functions。",[350,880,881,884],{},[42,882,883],{},"BaaS (Backend as a Service，后端即服务)","：比如云数据库（如你的 D1）、对象存储（如 R2）、身份认证服务。你直接调 API 就能用，不用自己建数据库服务器。前端直接连数据库，权限、登录、存储全用平台提供的现成功能，甚至不需要自己写后端代码。",[10,886,887],{},"serverless有四个特征，不用管服务器，不用打补丁，不用担心宕机问题，是零维护。从0到10000个并发，是由平台搞定，半夜没人访问的时候自动缩容到0，流量洪峰的时候能瞬间拉起几万个实例来抗住。按量计费，用多少算多少。函数通常由特定事件触发，比如一个http请求、一条数据库更新、一张图片上传。",[10,889,890],{},"那么具体业务该如何设计，肯定不可能把核心主干给剥离出去，我们可以把一些无状态、短生命周期、事件触发、按需运行的分离出去。比如说webhook接收器，接入了微信支付、GitHub、Stripe 等第三方服务。当用户支付成功时，第三方会发一个 HTTP 请求到你的服务器。或者是文件和图片处理，我们需要裁切为圆形、生成缩略图，加水印等操作，也可以分离出去，因为结合对象存储比如cloudflare R2\u002FAWS S3，一旦有文件上传，事件触发之后就会自动调用FaaS函数进行图片压缩，处理完了存回去，极其省钱且响应极快。一些定时任务，比如凌晨2点清理数据库过期验证码、同步第三方汇率等等，生成昨日报表等等，也可以，因为云厂商都支持定时触发FaaS，不需要专门搞一台机器挂个Crontab。边缘代理和BFF也可以。",[10,892,893],{},"适合作为baas拆分出去的比如说身份认证和权限管理，我们可以直接用firebase Auth， Supabase Auth都可以，或者国内的Authing 、腾讯云开发。文件存储比如用户头像、商品图片、视频、附件等等都可以自检搭建fastDFS或者minio，也可以直接用cloudflare r2\u002Faws s3、阿里云os、配合cdn、全球自带加速和极低的防盗链成本。之前提到的 Cloudflare D1 (基于 SQLite)，或者 Supabase（基于 PostgreSQL），己装 MySQL、Redis 还要搞主从复制、容灾备份 -> 直接用 Serverless DB，自带按需扩缩容，而且很多直接提供前端 SDK，前端可以直接查数据库（靠行级安全策略保护数据）。消息推送比比如app推送到手机、网站弹窗、邮件发送、短信发送等等，可以用baas平台接管，不需要自己维护推送服务器和长连接池。搜索引擎不需要自己搭建庞大的Elasticsearch 集群，直接用 Algolia 或 Meilisearch 的云服务。",[895,896,897],"style",{},"html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":52,"searchDepth":73,"depth":73,"links":899},[900,901,902],{"id":25,"depth":73,"text":25},{"id":331,"depth":73,"text":332},{"id":861,"depth":73,"text":862},"md",{"date":905,"tags":906},"2026-10-22",[907,908,909,861],"architecture","cloudflare","worker","\u002Farchitecture\u002Fcloudflare-workers",{"description":12},"architecture\u002FCloudflare Workers","hfjnMCGqiFnX9XkZRJCGKq8H7pAKgDw5NLAVQiarxTo",1792775383720]