WebHook
网页开发中的网络钩子(Webhook)是一种通过自定义回调函数来增加或更改网页表现的方法。这些回调可被可能与原始网站或应用相关的第三方用户及开发者保存、修改与管理。术语“网络钩子”由杰夫·林德塞(Jeff Lindsay)于 2007 年通过给计算机编程术语“钩子”(Hook)加上前缀得来

为什么我需要搭建一个 webhook
那可要从搭建这个博客系统说起了,由于该博客使用 hexo 搭建,所以每次更新博客需要部署一下然后才能生效。而我又不愿意每次写完都去部署,这样就埋下了一个 webhook 的坑!其实 webhook 就是一个回调地址每次推送都访问下那个地址然后做部署
搭建 webhook
其实搭建这个有很多第三方的库已经支持了,但是偏偏我选择了 gitee(可恶啊!!!)
1. 设置 gitee 的签名

如果你是 java 或者 python 搭建 webhoook gitee 有事例代码
下面使用 go 语言实现
1 2 3 4 5 6 7 8 9
| func Sign(secret string, time string) string { stringToSign := time + "\n" + secret key := []byte(secret) h := hmac.New(sha256.New, key) h.Write([]byte(stringToSign)) signData := h.Sum(nil) return base64.StdEncoding.EncodeToString(signData) }
|
2. 搭建后端服务
使用 gin 搭建 webhook 的后端服务
1 2 3 4 5
| func main() { r := gin.Default() router.RegisterRouter(r) r.Run(":3000") }
|
router 中的代码以及目录结构

其实我就是简单的分了一下目录结构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| webhook ├─Dockerfile // 打包 ├─Makefile // 部署 ├─boot.sh // sh脚本 ├─main.go // 程序入口 ├─utils | ├─response // 通用响应体 ├─internal | ├─router | | ├─gitee.go // gitee 的路由 | | └router.go // 总路由 | ├─handler // 处理函数 | | ├─blog.go | | └webhook.go ├─gitee | ├─errors.go // 错误常量码 | ├─event.go //一些事件的常量 | ├─gitee.go //gitee包 | ├─push_event_payload.go //推送事件的请求数据结构体 | ├─sign //签名包
|
3. 编写处理函数
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 39 40 41 42 43 44 45
| type GiteeService struct { hook *gitee.Webhook }
func NewGitee() *GiteeService { hook, _ := gitee.New(gitee.WithSecret(GITEESECRET)) return &GiteeService{ hook: hook, } }
func (g *GiteeService) Blog(c *gin.Context) { payload, err := g.hook.Parse(c.Request, gitee.PushEvents) if err != nil { if err == gitee.ErrEventNotFound { fmt.Printf("ErrEventNotFound %s\n", err) response.Err(c, err) return } fmt.Printf("unkonw error %s\n", err) response.Err(c, err) return } switch payload.(type) { case gitee.PushEventPayload: go func() { cmd := exec.Command("sh", "/root/app/blog/webhook.sh") output, err := cmd.CombinedOutput() if err != nil { fmt.Println(string(output)) fmt.Printf("command error %s\n", err) response.Err(c, err) return } fmt.Println(string(output)) }() response.Ok(c, nil) }
}
|
上面就是一个简单的处理函数,但是值得说的一个点是 为什么需要使用携程去处理 由于打包部署的时间比较久但是 gitee 的 webhook 请求时长为 5s
所以我们这个请求得开一个携程去处理否则请求将请求超时
4. 部署 webhook
由于我需要执行其他需要自动部署的 app 的 shell 脚本,然而我有不想讲整个目录软连接进去所以我就直接二进制部署了就没有使用 docker, 可以看到 Dockerfile 都还在 呜呜呜
下面是我的部署 shell 脚本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| #!/bin/bash path=/root/app/webhooks
cd $path git pull
port=3000
pid=$(lsof -t -i:$port)
if [ -n "$pid" ]; then echo "Killing process $pid" kill -9 $pid fi
outlog="$path/out.log" if [ -e "$outlog" ]; then rm "$outlog" fi
rm -rf $path/main go build -o $path/main . nohup $path/main >> $outlog &
|
先将之前的服务停止,然后再将日志清除,最后再后台运行。
5. gitee 配置 webhook
这个就简单了就将你的后台路由填进去然后测试一把就行


总结
以上就是搭建 webhook 的整个流程咯,实际上就是写个后端服务,然后当你出发 git 某个操作就会请求这个 url 然后执行你需要执行的代码。