Sorry, your browser cannot access this site
This page requires browser support (enable) JavaScript
Learn more >

在强大的 serverless 平台上写一个复读机(

vercel 是什么?

以下摘自 vercel 官网文档

Vercel is a platform for frontend frameworks and static sites, built to integrate with your headless content, commerce, or database.

We provide a frictionless developer experience to take care of the hard things: deploying instantly, scaling automatically, and serving personalized content around the globe.

We make it easy for frontend teams to develop, preview, and ship delightful user experiences, where performance is the default.

说人话!

简单来说,Vercel 是由 Next.js 团队打造的一个类似 GitHub Pages 的网页托管平台,同时也是强大的零配置静态资源和无服务器云计算(serverless) 部署平台。

一些废话

其实对于 serverless,大多数人都会有一个误区,认为 “serverless” 即 “无需服务器“ 。

“serverless” 的字面意义确实是无服务,这里的服务指的也是服务器,不管是单体应用还是微服务应用,我们都需要将自己的代码部署到服务器上,但 “serverless” 的提出,并不意味着我们不再需要物理服务器,而是指开发人员只需关心服务的业务逻辑,而无需关心关心服务器的状态、计算资源的调度、弹性伸缩、负载均衡、运维等。

也就是说,serverless 不是”无需服务器“,而是”无需你管服务器“。

vercel serverless fiction 的介绍及限制

vercel 的 serverless function 背后用是 AWS 的 lambda,因此可以部署在全球多个地区的 AWS 服务器,利用边缘网络使全世界的访客最快地访问资源。

目前,vercel 官方支持的几种后端语言是 node.js、Python、Go (beta)、Ruby (beta),详见 vercel 运行时文档

Serverless 的应用不会一直在线,也不会一直占用资源。换句话说,serverless 应用只会于你向其发送请求时按需调用。

由于使用的是 AWS 的 Lambda,所以 vercel serverless function 有 Lambda 的一些限制:

  1. 大小限制:单个 function 的大小应该限制在 250 MB(解压缩)或者 50MB(压缩后),这里面的大小包括了其引入的外部依赖
  2. 内存限制:运行内存最大为 1024MB (pro 用户为 3000MB)
  3. 超时限制:响应请求的超时时间最大为 5 秒(pro 用户为 15 秒,企业用户为 30 秒)
  4. 并发限制:对于免费用户来说,最大并发数量为 1000
  5. 请求 body 限制:request body 参数大小最大为 5 MB
  6. 部署区域限制:个人账号下只能听从官方的默认部署区域(美国华盛顿),企业账号可以部署到多个区域。

那么既然可以云端运行代码,是不是就意味着我们可以用它来干点什么?(

用 vercel 跑一个 Telegram bot!

既然 severless fiction 是按需调用的,用一般的长轮询(long polling)方式获取消息更新肯定是行不通了。这时候就需要祭出 Telegram 的 WebHook 了。

WebHook 是怎么工作的?

对于 Telegram bot 来说,利用 setWebhook 方法告知服务器一个 url, 服务器就会在于 bot 收到新消息时,通过 POST 方法将 json 格式的 Update 对象发送到指定的 url 地址。

对于响应消息,有两种选择:

  • https://api.telegram.org/bot<token>/method 发送 POST 请求

  • 直接将消息回应内容写在对于 Telegram 服务器的 response 中

对于 serverless 框架来说,第二种方法固然是更好的选择,但对于 Golang 来说,我并没有找到能很好处理 webhook 响应内容的 package

开整!

先从一个简单的复读机 bot 开始吧(

对于 Telegram bot API,我选择了github.com/go-telegram-bot-api/telegram-bot-api/v5这个 package

1
2
3
package api

import "github.com/go-telegram-bot-api/telegram-bot-api/v5"

对于在响应内容中回应消息,需要将 Method 写入响应的 json 中,所以先定义一个 Struct 用于生成 json:

1
2
3
4
5
type Response struct {
Msg string `json:"text"`
ChatID int64 `json:"chat_id"`
Method string `json:"method"`
}

vercel 的 Go runtime 需要一个参数为(w http.ResponseWriter, r *http.Request)的公开函数:

1
2
3
func Repeater(w http.ResponseWriter, r *http.Request) {
...
}

然后既可以在这个函数内写我们的逻辑代码了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
func Repeater(w http.ResponseWriter, r *http.Request) {
defer r.Body.Close()

// 读取请求 body
body, _ := ioutil.ReadAll(r.Body)

// 创建一个 bot update
var update tgbotapi.Update

// 解析请求 body 中的 json 到 bot update
err := json.Unmarshal(body, &update)
if err != nil {
log.Println(err)
return
}

if update.Message.Text != "" {
// 在控制台打印收到的消息
log.Printf("[%s] %s", update.Message.From.UserName, update.Message.Text)

// 创建响应内容并生成 json
data := Response{
Msg: update.Message.Text,
Method: "sendMessage",
ChatID: update.Message.Chat.ID,
}
msg, _ := json.Marshal(data)

// 在控制台打印响应内容
log.Printf("Response %s", string(msg))

// 向响应头添加 Content-Type
w.Header().Add("Content-Type", "application/json")

// 发送格式化输出
fmt.Fprintf(w, string(msg))
}
}

到这里,就可以到 vercel 部署我们的 bot 了:

  • 在 GitHub 新建一个 repo,上传代码到 repo 的 api 目录下
  • 注册 vercel 并连接 GitHub 账号,新建 Project 并选择你上传代码的 repo
  • 手动请求https://api.telegram.org/bot<token>/setWebhook?url=https://xxx.vercel.app设置 webhook

向你的 bot 发送一条消息试试,不出意外的话,它已经是复读机的形状了(

至此,你的第一个 serverless bot 就部署完成了

以上代码的完整版本可以在我的 Github repo 中找到

评论