vercel 是干啥的?

作者:Jeff Tian
链接:https://www.zhihu.com/question/529047706/answer/2576302166
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

多年前写的 Koa Js 服务,本来跑在服务器上,要一点花销。后来决定薅各大云厂商的羊毛,就将它容器化了,跑在免费的 Okteto 提供的 K8S 环境里。但是最近 Okteto 提供的 url 访问不了了,虽然发了邮件请 Okteto 帮忙协助,但是本着狡兔三窟的原则,决定再部署一个实例到其他的服务上。

于是将目光瞄准到 Vercel,Vercel 提供免费的 Serverless Function,虽然类似 AWS Lambda,但又不太一样,所以记录一下。如果只是将 koa 服务部署到 AWS lambda,那么只需要使用一个 serverless-http 的框架转化一下就好。关于薅 AWS Lambda 羊毛的文章已经写过多篇,参见:

zhuanlan.zhihu.com/p/41

zhuanlan.zhihu.com/p/35

Koa Js

Koa Js 是由 Express Js 的原班人马设计的 Web 框架,更小巧但是不再捆绑任何中间件,这一点也是我在将它部署到 Vercel 时碰到坑的原因。尽管它比 Express 新,但 Express.js 仍然更加流行,也许这也是 Vercel 内置对 Express.js 的支持的原因吧。

Express Js 目前的星标数在 57.6 K,而 koa 的星标数大约是它的一半多一点:

image.png

image.png

看了一下 koa 的贡献者列表,我居然也名列其中呢:

image.png

Vercel

Vercel 是一个用来部署前端应用的云平台,但也可以用来构建轻量级的事件驱动 API,并部署到它们的全球边缘网络

Vercel 的 Serverless Function 有些特别

传统 API 托管在运行着的服务器上。当应用需要扩展时,希望更低成本、更灵活、更安全、资源快速分配并启动等等,使用传统服务器很难做到。但是用 Serverless 就比较容易,因为仅仅是一些后端代码片段在无状态环境中运行着,它们由事件(比如 http 请求)触发并只在一次调用中存活。这可以全部自动化并且在毫秒级扩展。更好的是,不用再维护服务器了。开发者只需要关注业务逻辑——返回值的函数。

如果我们部署一个服务器程序到 Serverless Function,我们就为每个请求执行了一个完整的服务器实现,这是一个反模式,因为 Serverless 函数仍然是函数,只应服务于一个目的。将服务器程序部署在 Serverless Function 上,相当于强行将庞大的逻辑混杂在一个函数里。虽然这是一个反模式,但是羊毛在那里,不得不薅。对于有钱的企业级服务器程序,还是建议绕道。

Vercel 的 Serverless Function 和 AWS Lambda 很像,比如都是一个对外暴露 handler 函数的模块,但是特别之处在于其 handler 签名不一样。AWS Lambda 的 handler:

export default const handler = (event, context) => 'Hello World'

但是 Vercel 的 handler 接收一个 req 和 res 参数(github.com/Jeff-Tian/v/):

export default function handler(req, res) {
    const { name = 'World' } = req.query;
    return res.send(`Hello ${name}!`);
}

v.pa-pa.me/api/test?

image.png

这签名看起来很像是 Express.js 中间件,有意思的是,它真的支持完整的 Express.js 应用,只需要将入口文件放在 /api/index.js 里即可。

Vercel Serverless Function 对 Koa 的支持

经过实验,Vercel Serverless Function 是不支持 Koa.js 应用的。因为它的签名和 (ctx, next) => ctx.body = ‘Hello’ 这种 Koa.js 风格就不相容。

koa-to-express

想将 Koa 应用搬到 Vercel Serverless Function,但是不希望改已有的 Koa 代码,最自然的方式莫过于增加一个 adapter,将 koa 风格的中间件函数适配成 express.js 的中间件函数。于是找到了 koa-to-express 这个库。

增加 /api/index.js 文件

该 index.js 引用 Koa 应用的入口文件,并将它的中间件做个转换,伪装成一个 Express.js 应用。这样,原来的 Koa 应用在服务器环境中仍然照常运行,同时又可以在 Vercel Serverless Function 环境里运行。如果再使用 serverless-http,再在 AWS Lambda 里部署一个适配,那么就是名副其实的“狡兔三窟”了。

image.png

修复 koa-to-express 的一个 BUG

其实没有那么顺利,由于原 Koa 应用使用了 koa-router 这个中间件,触发了 koa-to-express 的一个 BUG。于是只能 Fork 了 koa-to-express ,在自己的版本中做了修复。虽然给原作者提交了 PR,但在他合并并发新版之前,我得临时使用自己的版本,于是要对 package.json 做个修改,在安装 koa-to-express 时,从自己的仓库里下载代码:

github.com/Jeff-Tian/v/

package.json:

-    "koa-to-express": "^3.1.4",
+    "koa-to-express": "git+https://github.com/jeff-tian/koa-to-express.git",

给它们的 PR 链接:github.com/xingxingted/

完成 /api/index.js

最终的 /api/index.js 文件如下:
github.com/Jeff-Tian/v/

const k2e = require('koa-to-express');

process.env.ROUTER_PREFIX = '/api';

const app = require('../app');

const expressApp = require('express')();

app.middleware.map(m => {
    expressApp.use(k2e(m));
})

module.exports = expressApp;

重定向

Vercel Serverless Function 默认将 /api/xxx 路由到 /api/xxx.js,所以 /api/xy/z,就不会被 /api/index 处理,所以需要增加一个 vercel.json 文件,将所有 /api/ 下的请求,重定向到 index.js:

{
  "rewrites": [{ "source": "/api/(.*)", "destination": "/api" }]
}

完成

效果和在服务器上运行 koa 一模一样:

1.本站默认解压密码为:xiaoqingtai.com
2.本站所有内容均由互联网收集整理,仅供大家参考、学习,禁止商用。
3.本站所有内容版权归原著所有,如有侵权请及时联系我们做删除处理。
请扫描下方二维码关注微信公众号或直接微信搜索“小青苔基地”关注
小青苔基地 » vercel 是干啥的?

发表评论