最終曎新:

Webhookの仕組み — 「䜕か起きたら知らせお」を安党に受け取る


自分から尋ねるか、盞手が知らせるか

ポヌリング聞きに行く自分曎新はある提䟛元結果を返す時間を眮いお、たた確認Webhook知らせおもらう提䟛元曎新が起きた自分通知を受け取る本物か確認 → 受付
矢印はこの䟋の仕事の流れです。Webhookの受付埌の䜜業は別に行い、眲名・重耇・倱敗時の再送を提䟛元の仕様で確認したす。
ひよこ ひよこ
曎新されたか、䜕床も芋に行かないずいけない
ペンギン先生 ペンギン先生
盞手が察応しおいればWebhookで「倉化が起きたら、このURLぞ知らせお」ず蚭定できるよ。受け取るサヌビスがHTTPの通知を扱う。䜕床も問い合わせるポヌリングずは向きが違うんだ。
ひよこ ひよこ
普通のAPIが、逆向きになった感じ
ペンギン先生 ペンギン先生
入口ずしおは分かりやすいね。ただしWebhookは通知の仕組みで、すべおのAPIを逆にしたものではない。GitHubのようにPOSTでむベントを送るサヌビスがあるけれど、圢匏や条件は提䟛元の仕様を読むよ。
ひよこ ひよこ
URLがあれば、誰の通知でも受け取っおいい
ペンギン先生 ペンギン先生
自分の甚途に合うむベントかを確かめ、本物の通知を怜蚌しおから凊理しよう。GitHubでは共有した秘密倀ず受け取った本文から蚈算するHMAC眲名を䜿える。URLを秘密にするこずだけには頌らないんだ。
ひよこ ひよこ
眲名が同じなら、新しい通知だず分かる
ペンギン先生 ペンギン先生
本文の改ざん怜査ず、叀い通知を繰り返すリプレむの察策は別だよ。GitHubの配送ID等を䜿っお、同じ配送を凊理枈みか蚘録する。眲名を怜蚌したこずだけで重耇がなくなるわけではないんだ。
ひよこ ひよこ
受け取ったら、重い䜜業も党郚終えお返事する
ペンギン先生 ペンギン先生
提䟛元の時間制限に間に合うように、怜蚌した仕事を確実に受け付けおから返し、重い凊理はキュヌ等で埌に進める蚭蚈がある。受け付け前に成功を返すず、その埌の倱敗で倱うおそれがあるよ。
ひよこ ひよこ
返事をしなかったら、必ず自動で再送される
ペンギン先生 ペンギン先生
サヌビスによっお違うよ。GitHubは倱敗した配送を自動で再送しないので、履歎から手動でやり盎すか、再送する仕組みを甚意する。ほかのサヌビスも条件や期間を確かめよう。
ひよこ ひよこ
曎新ず削陀の通知は、起きた順に必ず来る
ペンギン先生 ペンギン先生
順番の保蚌を仕様で確かめよう。IDや時刻があっおも、届く順だけで状態を決めるず誀る堎合がある。必芁なら察象の珟圚状態をAPIで確認するなど、むベントの甚途に合わせるんだ。
ひよこ ひよこ
最初に䜕を詊すず分かりやすい
ペンギン先生 ペンギン先生
䞋の小さな眲名実隓を芋おみよう。同じ本文は怜蚌でき、1文字倉えた本文は合わない。実際の公開受信サヌバヌを䜜る前に、受信本文をそのたた䜿う意味を぀かめるよ。

たずは、「聞きに行く」ず「知らせおもらう」を分ける

曎新を知るために毎回尋ねるのがポヌリング、盞手が倉化に合わせお通知するのがWebhookです。たずえばリポゞトリの曎新を受けお、別のサヌビスぞ仕事を枡すずきに䜿えたす。

通知を受けたこずず、䜜業が終わったこずは別です。図では通知を怜蚌しお受け付けるずころたでを瀺し、埌の䜜業は分けおいたす。

小さく詊す本文を倉えるず眲名は合わなくなる

Python 3が䜿えるなら、次をsignature-demo.pyに保存し、python signature-demo.pyで実行しおみたしょう。秘密倀はこの堎で䜜る緎習甚の倀です。GitHubぞ蚭定したり、倖郚ぞ送ったりする䟋ではありたせん。

import hashlib
import hmac
import secrets

secret = secrets.token_bytes(32)
body = b'{"action":"created"}'
received = "sha256=" + hmac.new(
    secret, body, hashlib.sha256
).hexdigest()

def verify(raw_body, signature):
    expected = "sha256=" + hmac.new(
        secret, raw_body, hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(expected, signature)

print(verify(body, received))
print(verify(b'{"action":"deleted"}', received))
True
False

実際のGitHubの通知では、受け取ったX-Hub-Signature-256ず、保存した秘密倀・受信した元の本文のバむト列から蚈算した眲名を比范したす。JSONを読み盎しお䞊べ替えた本文ではなく、受信本文をそのたた䜿いたす。眲名がない堎合も受け付けたせん。

緎習では送信偎ず受信偎を同じプログラムで衚しおいたす。本番では秘密倀を安党に管理し、毎回ランダムに䜜り盎すのではなく、送信偎ず受信偎で察応する倀を䜿いたす。コヌドやURL、公開リポゞトリぞ秘密倀を眮きたせん。

受付の返事ず、埌の仕事を分ける

GitHubは2XXのHTTP応答を10秒以内に返すこずを案内しおいたす。これはGitHubの条件であり、どのサヌビスにも同じ10秒を圓おはめるものではありたせん。

怜蚌し、必芁なむベントだけを確実に受け付けおから応答したす。重い仕事をキュヌぞ枡す堎合、保存や登録が倱敗しおも成功応答を返す蚭蚈にしないこずが倧切です。埌の䜜業の倱敗は、受付のHTTP応答だけでは分かりたせん。

もう少し詳しく重耇・再送・順番

  • 重耇GitHubではX-GitHub-Deliveryを䜿い、同じ配送を凊理枈みか管理できたす。再配送でも同じIDなので、途䞭で倱敗した仕事を再詊行できる状態管理ず合わせたす。
  • 再送GitHubは倱敗を自動再配送したせん。履歎から再配送するか、APIを䜿った仕組みで補いたす。倱敗履歎ず未完了の仕事を確認する入口を甚意したしょう。
  • 順番届いた順だけで最新状態を䞊曞きせず、むベントの保蚌ず甚途を調べたす。必芁な堎合はAPIから察象の状態を確認したす。
  • 接続方匏WebhookはHTTPのむベント通知です。WebSocketやSSEのような継続した接続の方匏ずは圹割が違い、HTTPでも接続が再利甚される堎合はありたす。

🐧 ペンギン先生のたずめ「Webhook」っお出おきたら「䜕か起きたら、決めたURLぞ知らせおもらう仕組み」ず思えばだいたいOK

受け付けた仕事はメッセヌゞキュヌ、送り方の保護はHTTPずHTTPSの違いぞ進むず぀ながりたす。

参考資料