日常记录

用 ESA 边缘函数把静态站点推到离用户最近的地方

边缘函数这个名字容易让人以为它只能写动态逻辑。实际上对一个内容不常变的站点来说,它更像是一个不需要运维的、全球分布的 Node 运行时。

2026-08-24边缘计算阅读约 9 分钟

我为什么会走到这条路

起初我的需求非常小:一个静态页面,绑上自己的域名,能正常访问就行。最直接的做法是在 ECS 上装 Nginx 把文件扔进去。但很快发现两个问题——一是 HTTPS 证书要自己续期,二是源站 IP 会直接暴露在公网,任何扫描都会打到机器上。

ESA 这类边缘加速产品同时解决了这两件事:证书由平台签发和续期,回源只对边缘节点开放。而它的「边缘函数」还提供了第三种可能——干脆不要源站。

三种部署形态的差别

形态需要源站内容更新方式适合场景
仅 DNS 解析是(ECS)改服务器上的文件备案核查期、需要固定出口 IP
加速回源是(ECS / OSS)改源站 + 刷新缓存有大文件、需要隐藏源站
边缘函数直出发布新版本代码内容以文本为主、更新不频繁

第三种最有意思:请求在边缘节点就被函数接住并返回,根本不产生回源。对一个博客来说,这意味着没有需要维护的机器。

函数怎么把一个请求接住

边缘函数的模型接近 Cloudflare Workers:你注册一个处理 fetch 事件的监听器,自己构造 Response

addEventListener('fetch', event => {
  event.respondWith(handle(event.request))
})

async function handle(request) {
  const path = new URL(request.url).pathname

  if (path === '/') {
    return new Response(INDEX_HTML, {
      headers: { 'content-type': 'text/html; charset=utf-8' }
    })
  }

  // 文章正文放 KV 里,避免每篇都编译进函数代码
  const post = await KV.get('post:' + path.slice(6))
  if (post) return new Response(render(post), {
    headers: { 'content-type': 'text/html; charset=utf-8' }
  })

  return new Response('Not Found', { status: 404 })
}

把 HTML 模板写在代码里、正文放在 KV 里,是一个很舒服的分界:样式改动要发版,内容改动只需写 KV,秒级生效。

配额上要注意:免费档的函数版本数量很少(个位数),本地反复试错很容易用完。我的做法是先发布到测试环境验证,确认无误才提交为正式版本。

踩到的三个坑

一、函数创建了,但域名访问仍然 404

函数本身不会自动接管任何域名。它需要一个「关联记录」把站点的某条 DNS 记录绑上去,请求才会进入函数。这个关联动作很容易漏,漏了的表现就是域名压根解析不到函数。

# 把站点记录绑定到函数
aliyun esa CreateRoutineRelatedRecord \
  --Name my-app --SiteId <siteId> --RoutingRule '<match-rule>'

二、默认测试域名不能当生产域名用

每个函数创建时会带一个平台分配的默认域名,形如 xxx.<hash>.er.aliyun-esa.net。它只适合调试,直接对外访问并不稳定,正式的站点还是要绑自己的域名。

三、国内覆盖必须先备案

如果加速区域选择中国内地,平台会校验域名的备案状态。没备案的域名只能选海外或全球,否则站点起不来。

这条路的代价

边缘函数不是万能的。它的执行有 CPU 时间上限,不适合重计算;冷启动行为和 Node 不一样,不能假定有本地磁盘;而且最重要的一点——它是运行时生成 HTML,构建期没有任何检查,链接写错了只能靠访问时才发现。

所以对我现在这个规模,我最终选了最朴素的方案:静态文件 + Nginx + 仅 DNS 解析。把边缘函数留给确实需要动态逻辑的场景。

不过这几种形态之间的切换成本很低,主要就是改一条 DNS 记录。等站点的核查期过去,想要加速随时可以把记录改成代理模式。

← 返回文章列表