下面的实现是我作为一个软件开发者的日常工作中的一个快速摘录。如果我遇到一个问题,并得出一个我认为值得分享的例子,我将把代码的要点放在这个网站上。它可能对其他偶然遇到相同任务的人有用。
下面的实现告诉你如何在Node.js中部署一个Github Webhook。就我个人而言,我正在使用这种GitHub Webhook来在Digital Ocean上自动部署我的网站。无需通过SSH进入我的Web服务器来手动部署我的网站,我的DigitalOcean实例上不断运行的Webhook可以确保(A)从GitHub提取最近的变化,(B)建立我的网站。
GitHub上的Webhook设置
首先决定你要为哪个GitHub仓库运行Webhook。然后,导航到该项目设置和Webhooks。在那里你可以为这个GitHub仓库创建一个新的Webhook。

首先,无论你是在DigitalOcean还是其他地方运行你的应用程序,最后,你只需要找出有可能与你的托管Webhook在下一步用Node.js实现通信的URL或IP地址。把这个地址放在Payload URL字段中。就我个人而言,我只是在这里使用IP地址和我将在Webhook的实现中引入的端口(例如:http://133.66.66.66:8080 )。
第二,将内容类型设置为application/json。第三,创建一个秘密字符串,不应该与其他人分享。最后,我们只希望在有人向我们的 GitHub 仓库推送新内容时收到事件。
使用 Node.js 的 GitHub Webhook
如果你没有一个正常运行的Node.js应用程序,可以看看这个最小的Node.js教程,以帮助你开始。最后,你的Node.js应用程序的Webhook所需要的一切就是以下的实现。
import http from 'http';
import crypto from 'crypto';
import { exec } from 'child_process';
const SECRET = 'MY_GITHUB_WEBHOOK_SECRET';
http
.createServer((req, res) => {
req.on('data', chunk => {
const signature = `sha1=${crypto
.createHmac('sha1', SECRET)
.update(chunk)
.digest('hex')}`;
const isAllowed = req.headers['x-hub-signature'] === signature;
const body = JSON.parse(chunk);
const isMaster = body?.ref === 'refs/heads/master';
if (isAllowed && isMaster) {
// do something
}
});
res.end();
})
.listen(8080);
该实现显示了一个在Node.js中运行的裸体HTTP服务器。一旦它被部署,它就会收到GitHub的Webhook请求;鉴于Payload URL被正确设置为你部署的Webhook。
还要确保将SECRET 替换为新的 GitHub Webhook 中的Secret。只有这样,只有你能对这个Webhook进行验证调用(见isAllowed boolean)。
此外,只有当有东西被推送到主分支时,我们才会在这个 Webhook 中做一些事情(见isMaster boolean)--如果你想用这个 Webhook 来部署你的 GitHub 仓库的最新版本,这是有意义的。如需进一步帮助,请交叉阅读DigitalOcean的这个教程。
部署GitHub Webhook
现在,我们要把 Webhook 作为运行中的服务部署到 DigitalOcean -- 或者你所使用的任何主机提供商。因此,请遵循以下步骤:
- 为你的Webhook项目创建一个独立的GitHub仓库。
- 克隆这个Webhook项目到你的网络服务器上。
- 确保它在你的网络服务器上运行,
npm start。
现在你可以在Github上为你创建Webhook的仓库执行一个样本请求。请求应该通过,你应该能够在以下两个地方看到一些:
-
- Github的Webhook控制台
-
- 通过你的Webhook项目的
console.log()
- 通过你的Webhook项目的
接下来,我们将使Webhook项目在你的Web服务器上成为一个持续运行的HTTP服务器--如果出现问题,它也会重启。我们将使用PM2--一个Node.js进程管理器--来在我们的Web服务器上运行应用程序。首先,通过命令行在你的Web服务器上全面安装PM2:
sudo npm install -g pm2
其次,运行你的应用程序。
pm2 start my-github-webhook
如果你需要让PM2为你运行一个npm脚本,你可以用以下命令来代替触发它。
pm2 start npm --name my-github-webhook -- start
PM2应该输出一个你所有正在运行的应用程序的进程列表。现在,你不需要再担心手工启动你的Node.js应用程序。PM2会处理好这个问题。如果你需要更多关于DigitalOcean上的PM2的阅读,请交叉阅读DigitalOcean上的这个教程。
自动网站部署
最后但同样重要的是,你需要在GitHub Webhook中实现必要的代码,以便自动部署你的网站或任何其他应用程序。例如,你可以用下面这行代码取代// do something 。
exec('cd /home/rwieruch/my-website && npm run build');
而你必须用你自己的路径和npm脚本来替换。如果执行中的命令变得冗长,可以考虑给你的项目--你要用Webhook部署的项目--一个bash脚本,执行所有内容来部署网站。
exec('cd /home/rwieruch/my-website && bash deploy.sh');
另外,如果你想在多个网络应用程序/网站部署中重复使用Webhook,你可以让执行脚本依赖于来自不同GitHub仓库的Webhook请求的传入。
import http from 'http';
import crypto from 'crypto';
import { exec } from 'child_process';
const SECRET = 'MY_GITHUB_WEBHOOK_SECRET';
const GITHUB_REPOSITORIES_TO_DIR = {
'rwieruch/my-website-one-on-github': '/home/rwieruch/my-website-one',
'rwieruch/my-website-two-on-github': '/home/rwieruch/my-website-two',
};
http
.createServer((req, res) => {
req.on('data', chunk => {
const signature = `sha1=${crypto
.createHmac('sha1', SECRET)
.update(chunk)
.digest('hex')}`;
const isAllowed = req.headers['x-hub-signature'] === signature;
const body = JSON.parse(chunk);
const isMaster = body?.ref === 'refs/heads/master';
const directory = GITHUB_REPOSITORIES_TO_DIR[body?.repository?.full_name];
if (isAllowed && isMaster && directory) {
try {
exec(`cd ${directory} && bash deploy.sh`);
} catch (error) {
console.log(error);
}
}
});
res.end();
})
.listen(8080);
这种方法需要你为所有需要自动部署的GitHub仓库创建具有相同秘密的GitHub Hooks。此外,每个要部署的网站/网络应用都必须有一个bash的deploy.sh文件。你可以在这里找到我的GitHub Webhook实现,它为我的网站提供动力。