Serverless 实践
Serverless 实践
本篇文章源自我自己的一个需求:我需要在博客中将链接转化为卡片(类似知乎或飞书中的链接转换功能)。但问题来了,我的博客是使用 Jekyll 生成的纯静态页面,如何来实现这个需求呢?
一张卡片中的内容至少要有 图标
标题
描述
三个要素,而这三个内容都是存放在页面的 <head>
标签中的,因此就不得不访问目标链接获取页面内容了。首先思考不引入后端的方案:
- 纯前端动态渲染应该是不可能的,因为有跨域请求的问题。(用 iframe 或许可以,但实现起来可能比较复杂而且 DOM 结构也更乱了)
- 在构建的时候就生成卡片,但如果目标网页有更新,就无法拿到更新后的内容了。
因此似乎不得不引入后端了。但这是一个很小的需求,专门搞一台服务器做 API 似乎有些 overkill,于是便想到了现在挺流行的 Serverless。
Function
需要做的事非常简单:访问一个 URL 拿到 HTML 后直接返回,至于 HTML 如何 parse 来获取感兴趣的数据,放在用户浏览器来处理。
先看价格
这个需求应该目前所有的 Serverless 产品都能实现,那主要还是看如何省(白)钱(嫖),下面是写作本文时的调研结果(不会更新,也许内容已过期):
产品 | Free Tier |
---|---|
AWS Lambda | 每月 100 万次免费请求,400000 GB-s 计算时间 |
Azure Functions | 每月 100 万次免费请求,400000 GB-s 计算时间 |
Vercel | 不限请求次数,每月 100GB 带宽,100 GB-h 计算时间 |
Cloudflare Workers | 每天 10W 次请求,免费 KV 存储 |
Google Functions | 每月 200W 次免费请求,5GB 流量 |
这里所有产品提供的免费套餐基本都能满足需求,所以选了可能使用最多的 AWS Lambda
,另外经过测试,AWS Lambda
在国内也是可以访问的。
AWS Lambda
开通的方式不再赘述,这里直接创建一个 Lambda Function,注意在创建时,需要打开「高级设置」,勾选「Enable function URL」选项,否则不能使用链接来调用 Function,并且将 Auth type 修改为「None」,因为需要所有用户都可以使用该 Function,另外还需要勾选 CORS 来支持跨域访问。
创建完毕后,还需要继续配置 CORS,切到「Function URL」的配置菜单中:
因为大多数 Serverless 产品都支持 Node.js
,因此为了以后可能会有的平台迁移需求,这里也使用 Node.js
来写该 Function 的逻辑。代码非常简单,就是发送一个 HTTPS 请求,但要注意处理 gzip 压缩的情况:
const https = require('https');
const zlib = require("zlib");
exports.handler = (event, context, callback) => {
const requestData = JSON.parse(event.body)
const req = https.request(requestData.url, (res) => {
let body = '';
let output = res;
if (res.headers['content-encoding'] === "gzip") {
output = zlib.createGunzip();
res.pipe(output)
res = output
}
output.on('data', (chunk) => body += chunk);
output.on('end', () => {
callback(null, {html: body});
});
});
req.on('error', callback);
req.end();
};
配置完成之后,就可以通过 cURL
工具来测试这个 Function:
curl "https://crijyxhk4hfjcnftlnx5fkhemu0lqaxd.lambda-url.ap-northeast-1.on.aws/" \
-H "Content-type: application/json" \
-d '{"url":"https://chenglu.me/blogs/effective-colab"}'
现在只需要加上前端的代码就可以实现这个功能了。
前端逻辑
因为并不是所有链接都需要转换为卡片,因此给需要转换的链接标签加一个特殊的 class card-link
,前端逻辑就比较简单了:
- 找出页面中所有的
a.card-link
- 获取
href
属性,发请求给 Lambda Function,获得页面 HTML - 解析 HTML 以渲染出期望的样子
前端代码就不展示了,感兴趣的可以直接浏览器 inspect 来看,放一些 show case 吧,样式致敬 Twitter 的卡片链接。
- GitHub 个人 / 团队主页的链接:
- GitHub 项目链接:
- B 站视频
- 油管视频
- 普通链接
后记
Serverless Function 还有许多其他的玩法,从结构化、KV 存储到机器学习推断,Function 都可以胜任。如果是业务逻辑不是特别复杂,使用 Function 来做后端可能是更有效的方式。