Webhook は、イベントが起きたときに相手のサービスからこちらへ通知してもらう仕組みです。 決済完了、GitHub への push、フォーム送信といった出来事が起きた瞬間に、相手側がこちらの URL へ HTTP リクエストを送ってきます。
取りに行くのではなく、届く
こちらから定期的に問い合わせるポーリングと比べると、通信量が少なく、通知までの遅延も小さくなります。一方で「相手のタイミングで、こちらのサーバーが動いている前提で届く」ため、受け側の設計はポーリングより気を使います。
受け口を作る前に決める4つ
- 署名検証 — 送り主が本物か確かめる。多くのサービスは共有シークレットで署名を付ける。署名検証なしのエンドポイントは、URLを知った誰でも偽の通知を送れる
- 冪等性 — 同じ通知は再送される前提で作る。冪等性がないと注文が二重に確定する
- 即座に 200 を返す — 重い処理はキューに積み、受信自体はすぐ終わらせる
- リプレイ対策 — 署名に含まれるタイムスタンプを見て、古すぎる通知は捨てる
タイムアウトが再送を呼ぶ
3つ目を軽く見ると連鎖事故になります。受信処理の中でメール送信や外部API呼び出しをすると、応答が遅れて送信側がタイムアウトと判断し、同じ通知を再送します。再送された処理もまた遅い——という繰り返しで、1件のイベントからメールが何通も出るという典型的な事故になります。 受信時にやるのは「署名検証・重複チェック・保存・202 か 200 を返す」までにとどめ、実処理は非同期に回すのが定石です。
押さえておきたい注意点
Webhook の URL は推測されにくいものにし、公開リポジトリやフロントエンドのコードに残さないでください。署名検証があっても、URL が知られていること自体が攻撃面になります。 ローカル開発では外部から到達できないため、トンネルサービスで一時的に受けるか、送信側が提供するテスト送信機能を使います。