EdgeOne Makers Edge Functions
请求从用户到你的服务器,中间会经过很多个边缘节点。Edge Functions 就是跑在这些节点上的轻量函数,能在请求到达你的源站之前就把事情处理掉。这一篇讲 Edge Functions 的概念、优势,以及怎么创建第一个 Edge Function 并处理请求和响应。
Edge Functions 是什么
Edge Functions 运行在全球各地的边缘节点上。用户发一个请求,离他最近的边缘节点就会执行你写的代码,不用把请求送到千里之外的中心机房。
打个比方: 传统服务器像是在北京开了一个仓库,全国的用户都得从北京发货。Edge Functions 则是在每个省都设了前置仓,用户要的东西直接从最近的仓库处理。
它和 Cloud Functions 的核心区别在Functions 概览里讲过,这里再强调一下 Edge Functions 的定位: 轻量、快速、每个请求都会走一遍。
Edge Functions 的优势
低延迟。代码跑在离用户最近的节点上,网络传输距离最短。改个请求头、做个鉴权判断,通常在几毫秒内就能完成。
高可用。边缘节点天然分布式,一个节点挂了其他节点顶上,不用担心单点故障。
节省源站压力。非法请求、过期缓存这些在边缘就拦截掉了,不用打到源站,源站的负载直接降下来。
按量计费。没有请求就不执行,不执行就不花钱。对比一台一直开着的服务器,空闲时段完全不产生费用。
创建第一个 Edge Function
第一步: 进入 EdgeOne 控制台
打开 EdgeOne 控制台,找到你的站点,进入”边缘函数”模块。点击”新建函数”,填写函数名称,比如 hello-world。
第二步: 编写函数代码
Edge Functions 使用 JavaScript 运行时,语法上接近标准 Web API。最简单的一个函数如下。
// 导出默认的 fetch 处理函数
export default {
async fetch(request, env, ctx) {
// 返回一段纯文本
return new Response('Hello from Edge Function', {
headers: { 'content-type': 'text/plain; charset=utf-8' }
});
}
};
这段代码做了一件事: 不管什么请求进来,都返回一句 “Hello from Edge Function”。fetch 是 Edge Functions 的入口函数,接收三个参数。
| 参数 | 类型 | 说明 |
|---|---|---|
| request | Request | 当前的 HTTP 请求对象 |
| env | Object | 环境变量和绑定的资源 |
| ctx | Context | 执行上下文,可以注册异步任务 |
第三步: 绑定路由
函数写好了,还得告诉 EdgeOne 哪些请求走这个函数。在”触发器”配置里添加路由规则,比如 example.com/hello/*,表示所有 /hello/ 开头的请求都走这个函数。
第四步: 部署
点击”部署”,函数就会推送到所有边缘节点。几秒后访问 https://example.com/hello/test 就能看到返回结果。
请求处理
实际使用中,你通常需要读取请求信息来做不同的处理。
读取请求方法和 URL
export default {
async fetch(request, env, ctx) {
// 获取请求方法: GET、POST 等
const method = request.method;
// 获取完整 URL
const url = new URL(request.url);
// 获取路径名
const pathname = url.pathname;
// 获取查询参数
const keyword = url.searchParams.get('keyword');
return new Response(JSON.stringify({
method: method,
pathname: pathname,
keyword: keyword
}), {
headers: { 'content-type': 'application/json' }
});
}
};
读取请求头
export default {
async fetch(request, env, ctx) {
// 读取单个请求头
const userAgent = request.headers.get('user-agent');
// 读取自定义请求头
const apiKey = request.headers.get('x-api-key');
// 检查某个请求头是否存在
const hasToken = request.headers.has('authorization');
return new Response(JSON.stringify({
userAgent: userAgent,
hasApiKey: apiKey !== null,
hasToken: hasToken
}), {
headers: { 'content-type': 'application/json' }
});
}
};
读取请求体
POST 请求通常带有请求体,Edge Functions 支持多种读取方式。
export default {
async fetch(request, env, ctx) {
// 只有 POST、PUT 等方法才有请求体
if (request.method === 'POST') {
// 方式一: 读成文本
const textBody = await request.text();
// 方式二: 读成 JSON(前提是客户端发的是 JSON)
// 注意: text() 和 json() 只能调一个,请求体只能读一次
const jsonBody = await request.json();
// 方式三: 读成 ArrayBuffer
// const bufferBody = await request.arrayBuffer();
return new Response(JSON.stringify({
received: jsonBody
}), {
headers: { 'content-type': 'application/json' }
});
}
return new Response('请用 POST 方法', { status: 405 });
}
};
响应处理
返回响应不只是 new Response() 这么简单,状态码、响应头都有讲究。
设置状态码和响应头
export default {
async fetch(request, env, ctx) {
// 正常返回 200,设置 JSON 响应头
return new Response(JSON.stringify({ message: 'success' }), {
status: 200,
headers: {
'content-type': 'application/json; charset=utf-8',
'cache-control': 'no-cache',
'x-custom-header': 'hello'
}
});
}
};
常见状态码用法
| 状态码 | 含义 | 典型场景 |
|---|---|---|
| 200 | 成功 | 正常返回数据 |
| 301 | 永久重定向 | 旧地址迁移到新地址 |
| 302 | 临时重定向 | 临时跳转,比如登录页 |
| 304 | 未修改 | 缓存命中,不用重新传输 |
| 400 | 请求有误 | 参数格式不对 |
| 401 | 未授权 | 缺少或无效的身份凭证 |
| 403 | 禁止访问 | 有凭证但权限不够 |
| 404 | 未找到 | 资源不存在 |
| 405 | 方法不允许 | 比如该用 POST 却用了 GET |
| 500 | 服务器错误 | 代码出异常了 |
重定向
export default {
async fetch(request, env, ctx) {
const url = new URL(request.url);
// 旧路径重定向到新路径
if (url.pathname === '/old-page') {
return Response.redirect('https://example.com/new-page', 301);
}
return new Response('Normal page');
}
};
返回 HTML 页面
export default {
async fetch(request, env, ctx) {
const html = `
<!DOCTYPE html>
<html>
<head><title>Edge Page</title></head>
<body>
<h1>这个页面由 Edge Function 动态生成</h1>
</body>
</html>
`;
return new Response(html, {
headers: { 'content-type': 'text/html; charset=utf-8' }
});
}
};
结合环境变量使用
实际项目中,API 密钥、数据库地址这些不能硬编码在代码里,要用环境变量。在概览里提过的 env 参数就是用来读环境变量的。
export default {
async fetch(request, env, ctx) {
// 读取在控制台配置的环境变量
const apiBaseUrl = env.API_BASE_URL;
// 用环境变量拼接口地址
const targetUrl = apiBaseUrl + '/data';
return new Response(JSON.stringify({
target: targetUrl
}), {
headers: { 'content-type': 'application/json' }
});
}
};
在 EdgeOne 控制台的函数配置里,找到”环境变量”模块,添加键值对就行。env.API_BASE_URL 就能读到对应的值。
速查卡片
| 要点 | 说明 |
|---|---|
| Edge Functions 运行位置 | 全球边缘节点,离用户最近 |
| 入口函数 | fetch(request, env, ctx) |
| request 参数 | 标准 Web Request 对象 |
| env 参数 | 环境变量和绑定资源 |
| 返回响应 | new Response(body, { status, headers }) |
| 读取 JSON 请求体 | await request.json(),只能读一次 |
| 重定向 | Response.redirect(url, statusCode) |
| 环境变量 | 控制台配置,代码里用 env.KEY 读取 |