Serverless实战:从入门到项目落地的完整指南

Tr° 俊轶 框架 阅读 2,511
赞 23 收藏
二维码
手机扫码查看
反馈

先跑个函数再说

说实话,我第一次接触 Serverless 时,脑子里全是“这玩意儿到底能干啥”。文档看了半天,不如直接上手写个函数。所以今天咱们不扯概念,先搞个能跑的。

Serverless实战:从入门到项目落地的完整指南

我用的是 Vercel(部署快、免费额度够用),你也可以用 AWS Lambda、阿里云函数计算,但 Vercel 对前端开发者最友好——写个 API 路由,git push 就自动部署了。

假设你有个 Next.js 项目(没的话新建一个也行),在 pages/api/hello.js 里写:

export default function handler(req, res) {
  res.status(200).json({ message: 'Hello from Serverless!' });
}

本地 npm run dev,访问 http://localhost:3000/api/hello,看到 JSON 就说明本地跑通了。接着 git push 到 Vercel 关联的仓库,等个十几秒,线上地址就出来了。亲测有效,比搭 Nginx + Node 服务省了至少半小时。

这个场景最好用:动态 API + 数据聚合

我最近做的一个项目需要从多个第三方接口拉数据,再合并返回给前端。以前得自己起个 Express 服务,还得考虑负载、日志、监控……现在?一个 Serverless 函数搞定。

比如从两个假接口拉用户信息和订单信息:

import fetch from 'node-fetch';

export default async function handler(req, res) {
  try {
    const [userRes, orderRes] = await Promise.all([
      fetch('https://jztheme.com/api/user/123'),
      fetch('https://jztheme.com/api/orders/123')
    ]);

    const user = await userRes.json();
    const orders = await orderRes.json();

    res.status(200).json({
      userId: user.id,
      userName: user.name,
      recentOrders: orders.slice(0, 5)
    });
  } catch (err) {
    console.error('Aggregation failed:', err);
    res.status(500).json({ error: 'Failed to fetch data' });
  }
}

注意:这里用了 node-fetch,因为 Vercel 的 Serverless 环境默认没有 fetch(Node.js 18 以下)。如果你用的是 Node.js 18+ 运行时,可以直接用原生 fetch,但为了兼容性,我建议显式装 node-fetch 并 import。

这种聚合场景简直是 Serverless 的天菜——请求来了就跑,跑完就停,不用管服务器是不是半夜挂了。而且按调用量计费,没流量就不花钱,对我们这种小项目太友好了。

踩坑提醒:这三点一定注意

别看 Serverless 写起来简单,我踩过的坑能填满一个泳池。重点说三个:

  • 冷启动延迟:函数长时间没被调用,下次触发会慢 1~3 秒(Vercel 免费版更明显)。解决方案?要么接受(对非关键接口),要么用 Pro 计划(保持常驻),或者前端加个 loading 提示。别指望完全消除,这是 Serverless 的物理限制。
  • 超时时间硬限制:Vercel 免费版函数最长执行 10 秒,AWS Lambda 默认 3 秒(可调到 15 分钟)。我之前有个 PDF 生成函数,处理大文件时老超时。后来拆成两步:先返回“任务已提交”,再用另一个函数轮询结果。或者干脆换方案——有些重任务还是放传统服务器吧。
  • 环境变量别硬编码:本地开发时图快,直接把 API Key 写代码里,一提交到 GitHub 就泄露了。正确做法是用平台提供的环境变量功能(Vercel 后台点几下就行),代码里读 process.env.API_KEY。上线前务必检查 .env 文件是否被 git 忽略!

还有个小细节:函数里别用 console.log 打印敏感数据(比如用户密码),日志可能被平台记录,有安全风险。调试时用 console.log 没问题,但上线前记得删掉。

高级技巧:用中间件封装通用逻辑

当函数多了,你会发现很多重复代码:鉴权、参数校验、错误格式化……这时候写个中间件层就很香。

我在项目里抽了个 withAuth.js

// middleware/withAuth.js
export default function withAuth(handler) {
  return async (req, res) => {
    const token = req.headers.authorization?.split(' ')[1];
    if (!token || !isValidToken(token)) {
      return res.status(401).json({ error: 'Unauthorized' });
    }
    return handler(req, res);
  };
}

function isValidToken(token) {
  // 你的验证逻辑,比如 JWT 解析
  return token === 'valid-token'; // 简化示例
}

然后在具体函数里套一层:

import withAuth from '../../middleware/withAuth';

async function handler(req, res) {
  // 你的业务逻辑
  res.json({ data: 'protected content' });
}

export default withAuth(handler);

这样每个需要鉴权的函数只要 import 一下就行,不用重复写 if 判断。类似地,你还能做参数校验中间件、日志中间件。不过注意:中间件别嵌套太多层,否则调试时 stack trace 会很乱。

另外,Vercel 最近支持 Edge Functions(基于 Deno),启动更快,但生态还不成熟。我试过一次,发现 node-fetch 不能用,得改用 Web 标准的 fetch。如果你的函数逻辑简单,可以试试,但复杂项目建议先用传统 Serverless Functions。

不是万能药,但值得用

Serverless 不是银弹。它适合短时、无状态、事件驱动的任务。如果你要跑 WebSocket 长连接、或者需要持久化内存缓存,那还是老老实实用传统服务器吧。

但对大多数前端项目来说,80% 的后端需求(比如表单提交、数据代理、简单 webhook)都能用 Serverless 搞定。省下的运维时间,够你多写几个 feature 了。

以上是我踩坑后的总结,希望对你有帮助。这个技术的拓展用法还有很多(比如结合数据库触发器、定时任务),后续会继续分享这类博客。有更优的实现方式欢迎评论区交流——毕竟我上次那个 PDF 生成方案,到现在还在找更好的解法……

本文章不代表JZTHEME立场,仅为作者个人观点 / 研究心得 / 经验分享,旨在交流探讨,供读者参考。
发表评论

暂无评论