从"能跑"到"能打"。读完这 Part,你能用边缘函数、缓存策略、CLI 流水线和定时任务,把 Agent 与 Web 服务做成生产级工程,而不只是又一个 demo。
11.1 我为什么不再自己买服务器
2月前我接了个需求:给一个活动页加"实时倒计时 + 区域限流"。第一反应是自己开台 CVM,写个 Go 服务。算下来:机器钱、运维、扩容、被攻击的担心。我后来想,这种"请求来了算一下就返回"的逻辑,凭什么要我养一台服务器?
Makers 的边缘函数正好吃这个场景。
11.2 它怎么把代码铺到 3200+ 节点
先给结论:Pages Functions 运行在 EdgeOne 3200+ 边缘节点上,你的代码不用落在一台固定服务器,而是被调度到离用户最近的节点执行。
| 维度 | 自建服务器 | Pages Functions | 标叔的结论 |
|---|---|---|---|
| 部署位置 | 单区域一台 | 3200+ 边缘节点 | 就近响应 |
| 扩容 | 自己加机器 | 平台弹性 | 不用操心峰值 |
| 延迟 | 跨地域高 | 就近低 | 体验直接好 |
| 运维 | 自己盯 | 平台管 | 省一个人 |
最后一列"运维"。边缘函数把"机器"这件事从你的待办里删了。
11.3 路由就是目录:/functions 约定优于配置
Makers 不让你写路由表。你在项目根目录建一个 functions/ 文件夹,里面每个 .js 文件自动变成一条路由。
// functions/index.js -> example.com/
// functions/hello-pages.js -> example.com/hello-pages
// functions/api/users/list.js -> example.com/api/users/list
文件结构即路由表。没匹配到的请求,自动回退到静态资源。
约定优于配置,省的是你维护路由文件的心智。新手最容易犯的错,是去翻"路由配置在哪",其实根本没那个东西。
11.4 动态路由:[id] 与 [[default]]
真实 API 不可能每个 ID 写一个文件。Makers 支持两种动态段:
// functions/api/users/[id].js -> 匹配 /api/users/1024(单级)
// functions/api/[[default]].js -> 匹配 /api/books/list(多级 catch-all)
// functions/api/users/[id].js
export function onRequestGet({ params }) {
return new Response(`用户 ID 是 ${params.id}`);
}
注意:[id] 只吃一级路径,/api/users/vip/1024 它接不住;[[default]] 能吞多级。选错会 404,我踩过。
11.5 Handlers:按 HTTP 方法分派
一个文件能同时处理多种方法,也能只认一种:
export function onRequest(context) { /* 所有方法 */ }
export function onRequestGet(context) { /* 只认 GET */ }
export function onRequestPost(context) { /* 只认 POST */ }
// 还有 Put / Delete / Patch / Head / Options
context 里你能拿到:request(请求对象)、params(动态路由参数)、env(环境变量)。
警告:边缘函数不支持
addEventListener,别拿传统 Service Worker 那套来写。它只认 Function Handlers。我第一次写就栽在这。
11.6 三个真实示例:geo / KV / supabase
(1)拿客户端地理位置——context.request.eo.geo 直接给你:
export function onRequest({ request }) {
const geo = request.eo.geo;
return new Response(JSON.stringify({ geo }), {
headers: { 'content-type': 'application/json; charset=UTF-8' },
});
}
(2)用 KV 存访问数——my_kv 是你在项目里绑定的命名空间变量名:
export async function onRequest({ env }) {
const n = Number(await my_kv.get('visitCount')) + 1;
await my_kv.put('visitCount', String(n));
return new Response(JSON.stringify({ visitCount: n }));
}
(3)连三方数据库 supabase:
import { createClient } from '@supabase/supabase-js';
export async function onRequest({ env }) {
const supabase = createClient(env.supabaseUrl, env.supabaseKey);
const { data } = await supabase.from('users').select('*');
return new Response(JSON.stringify({ users: data }));
}
标叔的建议:示例三连三方库,记得把依赖装进项目,别以为边缘节点自带。详见 §13 的环境变量与 §14 的 includeFiles。
11.7 边缘函数不是银弹
它跑的是 V8、ES6、标准 Web API(Fetch / Cache / Crypto / Stream 都有)。但单函数有运行时长上限,重计算别往里塞。
能在边缘算的"轻逻辑"——鉴权、改写、限流、拼装——用它;要算半天的重活,留给云函数或你的后端。
下一章,我们让这些静态资源和函数响应"快到极致"。