Webhook到底是個啥?

伺服器: Jenkins Server
Git Server
App Server
關鍵詞: nodejs
ngrok
github webhook
在配置Jenkins實現前端自動化構建的過程中,對於自動化的過程理解很模糊,只是知道Jenkins伺服器,Git倉庫和後端應用伺服器這三個概念。
- git push之後,Git如何通知Jenkins對應Job的工作區實時構建 ?
答案就是:Git webhook機制發出請求,告知Jenkins伺服器你要自動構建了。
webhook與非同步程式設計中"訂閱-釋出模型"非常類似,一端觸發事件,一端監聽執行。
如果僅僅想學習webhook,可以直接閱讀。但是一定要注意,知識點是"非同步程式設計模型",webhook僅僅是它的一個實現。
開啟正文!
以github webhook,koa,ngrok學習Webhook。
維基百科:
在web開發過程中的webhook,是一種通過通常的callback,去增加或者改變web page或者web app行為的方法。這些callback可以由第三方使用者和開發者維持當前,修改,管理,而這些使用者與網站或者應用的原始開發沒有關聯。 webhook
這個詞是由Jeff Lindsay在2007年在電腦科學hook專案第一次提出的。
- Webhooks是"user-defined HTTP回撥"。它們通常由一些事件觸發,例如"push 程式碼到repo",或者"post 一個評論到部落格"。
- **當事件發生時,源網站可以發起一個HTTP請求到webhook配置的URL。**配置之後,使用者可以通過在一個站點觸發事件,之後再呼叫另一個站點的行為。可以是任何操作。
- 普通使用者可以使用 CI系統 或者通知bug追蹤系統觸發build。
- 由於webhook使用HTTP協議,因此可以直接被整合到web service。所以他們有時會被用來構建訊息佇列服務,例如一些RESTful的例子:IronMQ和RestMS。
以Github Webhook為例,學習webhook。
一、基礎部分
Webhook 允許我們通過在Github.com訂閱事件後構建後或者安裝Github應用。當其中之一的事件被觸發時,我們可以傳送HTTP POST請求到webhook的配置URL。**Webhook可以用作升級一個issue追蹤,觸發CI構建,升級一個後端映象,或者甚至是部署你的生產伺服器。**只有想不到,沒有做不到。
事件
在配置webhook的時候,你可以選擇自己想要接收的事件。你甚至可以選擇參加觸發所有事件。只有訂閱特殊的需要的事件,可以有效限制伺服器HTTP請求數。可以通過API或者UR隨時訂閱事件。預設情況下,webhook只訂閱push事件。
每個事件與一個動作集合聯絡,這些動作可以在你的組織或者repo中發生。例如,如果你訂閱了issues事件,你將在issue open,close以及labeled時接收到detailed payload。
下面是一些可用的事件:
Name | Description |
---|---|
* |
Any time any event is triggered ( ofollow,noindex">Wildcard Event ). |
check_run |
Any time a check run is created, requested, or rerequested. |
check_suite |
Any time a check suite is completed, requested, or rerequested. |
commit_comment |
Any time a Commit is commented on. |
push |
Any Git push to a Repository, including editing tags or branches. Commits via API actions that update references are also counted. This is the default event. |
......
載荷
每一個事件型別都有一個指定的與相關事件資訊有關的payload格式。所有的事件載荷都是事件型別的載荷映象,push除外,因為他有更加詳細的webhook負載。
除了每個事件的documented欄位,webhook負載包含了執行事件的使用者以及組織和或repo,對於一個Github App的webhook來說,它包含installation。在PullRequestEvent payload中有示例。
傳送報文頭
傳送到webhook配置URL的HTTP POST負載會包含幾個指定的報文頭。
Header | Description |
---|---|
X-GitHub-Event |
觸發分發的事件型別。 |
X-GitHub-Delivery |
唯一識別分發的GUID。 |
X-Hub-Signature |
HMAC十六進位制的響應體。如果secret配置了,這個頭資訊將被髮送。HMAC十六進位制由sha1雜湊演算法生成,secret作為HMAC的key。 |
User-Agent也將會加上字首GitHub-Hookshot/. 示例:
POST /payload HTTP/1.1 Host: localhost:4567 X-Github-Delivery: 72d3162e-cc78-11e3-81ab-4c9367dc0958 X-Hub-Signature: sha1=7d38cdd689735b008b3c702edd92eea23791c5f6 User-Agent: GitHub-Hookshot/044aadd Content-Type: application/json Content-Length: 6615 X-GitHub-Event: issues { "action": "opened", "issue": { "url": "https://api.github.com/repos/octocat/Hello-World/issues/1347", "number": 1347, ... }, "repository" : { "id": 1296269, "full_name": "octocat/Hello-World", "owner": { "login": "octocat", "id": 1, ... }, ... }, "sender": { "login": "octocat", "id": 1, ... } } 複製程式碼
Ping 事件 ping事件負載
| Key | Value | | --- | --- | | zen | Random string of GitHub zen | | hook_id | The ID of the webhook that triggered the ping | | hook | The [webhook configuration](https://developer.github.com/v3/repos/hooks/#get-single-hook) | 複製程式碼
GitHub App 當你註冊一個新的GitHub App時,GitHub傳送一個ping事件到webhook URL。事件的包含app_id。
{ "hook":{ "type":"App", "id":11, "active":true, "events":["pull_request"], "app_id":37, ... } } 複製程式碼
二、實驗開始
1. 配置並建立Webhook
- 配置Github監聽事件型別
- Payload URL接收webhook POST請求的伺服器埠。
- Content型別
- application/json會將JSON payload直接放置POST的body中。
- application/x-www-form-urlencoded型別將JSON payload作為payload引數傳送。
- Secret
- 使得webhooks更加安全的一個配置。
- Events
- Events是webhook的核心。只要對儲存庫執行某項操作,就會觸發這些webhook,伺服器的有效負載URL會攔截並執行操作。
- Events是webhook的核心。只要對儲存庫執行某項操作,就會觸發這些webhook,伺服器的有效負載URL會攔截並執行操作。
2. 配置接收和管理負載的伺服器
- 安裝ngrok並且做公網對映
./ngrok http 4567 複製程式碼
將生成的只有8小時有效時間的url複製到Payload URL。
http://785902b9.ngrok.io/payload 複製程式碼
- 寫接收/payload路徑的nodejs服務
var Koa = require('koa'); var Router = require('koa-router'); var app = new Koa(); var router = new Router(); router .post('/payload', (ctx, next) => { console.log(ctx); }) app .use(router.routes()) .use(router.allowedMethods()); app.listen(4567); 複製程式碼
執行以下命令啟動服務:
node server.js 複製程式碼
- 在Issues new 一個Issue。
- 本地的服務監聽到issue事件之後,會打印出webhook的資訊
{ request: { method: 'POST', url: '/payload', header: { host: '785902b9.ngrok.io', accept: '*/*', 'user-agent': 'GitHub-Hookshot/22e0d92', 'x-github-event': 'issues', 'x-github-delivery': 'cde0a020-7c48-11e8-9c35-c1d90e4891c8', 'content-type': 'application/x-www-form-urlencoded', 'x-hub-signature': 'sha1=9f4873803f9615615e02f7dec856778ebfc201be', 'content-length': '10929', 'x-forwarded-for': '192.30.252.44' } }, response: { status: 404, message: 'Not Found', header: {} }, app: { subdomainOffset: 2, proxy: false, env: 'development' }, originalUrl: '/payload', req: '<original node req>', res: '<original node res>', socket: '<original node socket>' } 複製程式碼
3.測試Webhooks
在每一個Webhook下都有一個觸發事件記錄列表。

單擊後會展開webhook的請求和響應。


4.在Github和server設定token
- 不要硬編碼,使用安全隨機的方式生成十六進位制hash token
- 將生成的token複製到webhook的secret配置處,再將其儲存到伺服器專門的本地變數中
- token hash在請求報文頭的X-Hub-Signature
- 可以設定服務端token校驗,若本地儲存的token與Github傳來的token不一致,報500
三、實驗分析
- 訂閱: github repo訂閱
issue
webhook event - 釋出: 由來自世界各地的開發者建立issue後,觸發trigger,發請求到Payload URL,發請求到伺服器
- 處理: URL對應的伺服器,解析請求,做出響應
四、引申分析Jenkins CI
- git push之後,Git如何通知Jenkins對應Job的工作區實時自動構建?
- 訂閱: Git倉庫訂閱
push
webhook event - 釋出: 某個開發人員本地git push後,觸發Git repo的trigger,發請求Jenkins伺服器
- 處理: Jenkins伺服器解析請求,進行自動構建
- 訂閱: Git倉庫訂閱
- 核心知識點是什麼? "釋出-訂閱" 事件非同步程式設計模型,要注意這個模型是 只針對Git repo自身 的,它訂閱了來自local的push事件,觸發者則是某一個開發者的git push操作。
五、釋出訂閱者模型引申
- vue元件通訊
$emit
$on
- vue非同步優先佇列,
$nextTick()
自身訂閱釋出 - vuex全域性狀態樹 提交mutation
commit()
隱式監聽 - webhook event 新增請求報文頭
- nodejs middleware next
- child_process.fork 多執行緒通訊
- ARP協議 私有區域網內的機器間通訊
- nodejs EventEmitter
- vuex plugin subscribe
- 基於Dijkstra演算法的鏈路狀態路由 動態更新路由表
如果還是不懂,建議先閱讀樸靈大神的《深入淺出nodejs》的非同步章節,並且涉獵大量的非前端技術,並實踐。
不過對於這篇博文來說, webhook是Git的一種機制,可用於前端自動化構建 是關鍵知識點。
當然,關於這篇博文,其實有些流程還不是很清晰,文章內容可能在我做完一次完整的 Jenkins自動化構建實驗 後更新。
參考:
- www.wikiwand.com/en/Webhook
- developer.github.com/webhooks/
- developer.github.com/webhooks/co…
- developer.github.com/webhooks/te…
- developer.github.com/webhooks/se…
- blog.csdn.net/boling_cava…
That it !