什么是webhook Webhook 是一个 API 概念,是微服务 API 的使用范式之一,也被成为反向 API,即前端不主动发送请求,完全由后端推送;
GtiHub中就存在这种功能,通过创建一个GitHub的webhook可以实现项目的自动部署,issues的自动推送等功能;
如何创建GitHub的webhook 首先我们要了解它的工作流程:
sequenceDiagram
Github Webhook ->> API Service: 发送POST请求,带有特殊Header,以及payload
API Service ->> Shell: 子进程启动对应脚本
API Service ->> Github Webhook: 返回200状态码,及其他自定义信息
编写webhook接口
flowchart LR
A[校验是否是github发送的请求] -->|是| B[执行构建脚本]
A --> |不是| C[返回UNAUTHORIZED]
此处以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 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 , ) {} 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 , }; } 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 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
flowchart LR
A[点击settings选项卡] --> B[点击webhooks]
B --> C[点击add webhook]
C --> D[等待发送ping请求]