什么是webhook

Webhook 是一个 API 概念,是微服务 API 的使用范式之一,也被成为反向 API,即前端不主动发送请求,完全由后端推送;

GtiHub中就存在这种功能,通过创建一个GitHub的webhook可以实现项目的自动部署,issues的自动推送等功能;

如何创建GitHub的webhook

首先我们要了解它的工作流程:

编写webhook接口

此处以nest.js创建的接口为例

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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
// webhook.controller.ts
import {
Controller,
HttpException,
HttpStatus,
Logger,
Post,
Req,
} from '@nestjs/common';
import { Request } from 'express';
import * as crypto from 'crypto';

import { WebhooksService } from './webhooks.service';
import { ConfigService } from 'src/config/config.service';

@Controller('webhooks')
export class WebhooksController {
private Logger = new Logger(WebhooksController.name);
constructor(
private readonly webhooksService: WebhooksService,
private readonly config: ConfigService,
) {}
/**
* 校验github webhook设置的secret的方法
**/
private verify_signature(req: Request, deploy: string) {
if (!req.headers['x-hub-signature-256']) {
return false;
}
const signature = crypto
.createHmac(
'sha256',
this.config[
`webhookSecret${deploy.replace(/^\S/, (s) => s.toUpperCase())}`
],
)
.update(JSON.stringify(req.body))
.digest('hex');
const trusted = Buffer.from(`sha256=${signature}`, 'ascii');
const untrusted = Buffer.from(
req.headers['x-hub-signature-256'] as string,
'ascii',
);
return crypto.timingSafeEqual(trusted, untrusted);
}

private deployHandler(req: Request, deploy: string) {
if (!this.verify_signature(req, deploy)) {
this.Logger.error('Unauthorized');
this.Logger.error(`headers: \n${JSON.stringify(req.headers)}`);
this.Logger.error(`body: \n${JSON.stringify(req.body)}`);
throw new HttpException('Unauthorized', HttpStatus.UNAUTHORIZED);
}
if (req.headers['x-github-event'] === 'push') {
return {
message: this.webhooksService[`${deploy}Deploy`](),
statusCode: 200,
};
}
// 这里是github webhook 发送除了push之外请求时的返回,如果有需要自行判断事件类型进行处理
return {
message: 'webhook no handler',
statusCode: 200,
};
}

@Post('blog')
blog(@Req() req: Request) {
return this.deployHandler(req, 'blog');
}
}

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
// webhook.service.ts
import { Injectable, Logger } from '@nestjs/common';
import { spawn } from 'child_process';

@Injectable()
export class WebhooksService {
private readonly Logger = new Logger(WebhooksService.name);

constructor() {
this.Logger.log('webhooks create...');
}

blogDeploy() {
this.Logger.log('deploy init');
// 启动子进程
const deploy = spawn('sh', ['scripts/blog.deploy.sh']); // 执行构建脚本
deploy.stdout.on('data', (data) => {
this.Logger.log(data);
});
deploy.stderr.on('data', (data) => {
this.Logger.log(data);
});
deploy.stdout.on('end', () => {
this.Logger.log('deploy end');
});

deploy.stdout.on('error', (err) => {
this.Logger.error(err);
});
// 我这里不管子进程执行进度,直接返回成功,想同步执行的自己改
return 'success';
}
}

创建github webhook

github

github

github