Anda memiliki layanan yang perlu bereaksi ketika sesuatu terjadi di tempat lain. Pembayaran terkonfirmasi. Catatan pelanggan berubah. Repositori menerima push. Anda bisa memeriksa API setiap menit dan menghabiskan siklus dengan bertanya-tanya 'apakah ada yang baru?' secara berulang-ulang, atau Anda bisa membiarkan sistem sumber memanggil Anda ketika event terjadi.
Itu di mana artikel contoh web hook biasanya berhenti. Mereka menampilkan rute, mencetak tubuh JSON, mengembalikan, dan mengatakan selesai. Versi itu berfungsi dengan baik hingga seseorang mengirimkan permintaan palsu, mengulangi permintaan yang valid, atau handler Anda rusak karena framework memproses tubuh sebelum verifikasi tanda tangan. 200Panduan ini mengambil jalur yang akan digunakan di produksi. Contoh-contohnya kecil sehingga bisa dicopy, tetapi mereka termasuk bagian yang penting: pengolahan tubuh mentah, verifikasi HMAC, pengecekan timestamp, pengakuan cepat, dan debugging yang praktis.
Tabel Konten
Apa Itu Webhook dan Mengapa Menggunakannya
- Mengapa Menggunakan Webhook
- Anatominya Permintaan Webhook HTTP
- Bagaimana Mengamankan Verifikasi Tanda Tangan Webhook
- Melindungi dari Serangan Ulang
- Membangun Penerima Webhook di Node.js
- Membangun Penerima Webhook di Python
- Membangun Penerima Webhook di Go
- Teknik Debugging yang Paling Penting
- Daftar Periksa untuk Webhook yang Siap Digunakan
- Faq tentang Webhook
Apa itu Webhook dan Mengapa Menggunakannya?
Pemberi tagihan Anda menandai tagihan sebagai dibayar pada 02:13. Jika aplikasi Anda belajar tentang hal itu pada 02:14, pelanggan mendapatkan akses segera. Jika aplikasi Anda belajar tentang hal itu pada siklus polling berikutnya, mereka menunggu, dukungan mendapatkan tiket, dan log Anda penuh dengan kebisingan yang tidak perlu. Webhook menyelesaikan masalah waktu dengan mengirimkan panggilan balik HTTP ketika event terjadi.
Dalam hal praktis, sebuah webhook adalah POST yang dikendalikan oleh event dari satu sistem ke sistem lain. Pemberi mendeteksi perubahan, seperti pembayaran, atau aktivitas repositori, dan mengirimkan data event ke URL yang Anda kendalikan. Ini menghilangkan loop invoice.paid, order.createdapakah ada yang baru? push yang terus-menerus yang dibuat oleh polling dan mengurangi banyak permintaan yang sia-sia.
This pattern shows up in real systems because it maps cleanly to business events. Stripe posts payment outcomes. GitHub posts repository activity. Shopify posts order updates. The shape is simple, but production behavior is not. A webhook that updates money, access, or inventory deserves the same care as any public API endpoint, especially once retries, duplicates, and untrusted traffic enter the picture.
Model mental yang membantu
Cara yang berguna untuk menggambarkan aliran webhook adalah sebagai empat bagian yang bekerja bersama:
- Sistem sumber. Layanan yang mendeteksi peristiwa.
- Tujuan akhir. Rute HTTP Anda yang menerima peristiwa tersebut.
- Peristiwa. Perubahan yang dinamai, seperti
invoice.paidataupush. - Payload. Badan permintaan dengan detail yang dibutuhkan oleh code Anda.
Pemberi data mengirimkan fakta tentang sesuatu yang sudah terjadi. Tugas Anda adalah untuk memverifikasi pengirim, memastikan permintaan masih segar, dan menerapkan perubahan sekali. Bagian terakhir itu lebih penting daripada banyak tutorial dasar yang mengabaikannya. Pada produksi, pengiriman ganda adalah perilaku normal, bukan kasus sampingan.
Aturan praktis: Gunakan webhooks untuk pembaruan berdasarkan peristiwa. Gunakan polling untuk bacaan yang dijadwalkan, backfills, atau pemberi data yang tidak menawarkan peristiwa keluar.
Untuk tim yang membangun aplikasi lebih luas otomasi alur kerja dan integrasi data, webhooks biasanya menjadi lapisan event yang menjaga sistem tetap sinkron tanpa lalu lintas permintaan yang tidak perlu. Jika Anda bekerja pada layanan yang berat integrasi, Capgo’s artikel pengembangan backend bermanfaat sebagai konteks karena masalah inti muncul di sekitar retries, antrian, observabilitas, dan pengelolaan gagal.
Apa yang berhasil dan apa yang gagal di produksi
Konfigurasi yang dapat bertahan baik biasanya dirancang untuk menjadi menarik. Berlangganan hanya pada event yang Anda butuhkan. Pastikan endpoint Anda terbatas berdasarkan penyedia atau keluarga event. Simpan ID event untuk mencegah pengiriman ulang yang tidak perlu. Kembalikan respons cepat 2xx setelah permintaan diverifikasi dan dikirim ke antrian, lalu jalankan logika bisnis yang lebih lambat secara asinkron.
Versi yang rapuh mudah dikenali. Satu endpoint umum mengelola segalanya. Pengecekan tanda tangan get skipped selama pengujian awal dan tidak pernah kembali. Pengolah menulis langsung ke tabel kritis sebelum memeriksa apakah event tersebut autentik atau sudah kadaluarsa. Itu berhasil dalam demo dan gagal di bawah badai retries, gangguan penyedia, atau penyerang yang merekam permintaan lama.
Perbandingan itu menentukan sisa panduan ini. Versi hello world dari penerima webhook kecil. Versi yang siap produksi menambahkan verifikasi tanda tangan, pertahanan ulang, pengelolaan duplikat, dan hook debugging dari awal.
Anatomi Permintaan HTTP Webhook
Sebelum menulis code, membantu untuk melihat permintaan sebagai HTTP mentah bukan sebagai objek framework. Webhook biasanya adalah HTTP POST ke endpoint publik dengan header dan tubuh JSON.
A permintaan HTTP sederhana
POST /webhooks/orders HTTP/1.1
Host: your-app.example
Content-Type: application/json
User-Agent: Provider-Webhooks/1.0
X-Webhook-Signature: sha256=abc123example
X-Webhook-Timestamp: 1712345678
{
"event": "order.created",
"id": "evt_123",
"data": {
"order_id": "ord_456",
"status": "created"
}
}
Bagian penting adalah sederhana:
- Methode. Pada prakteknya, pengiriman webhook biasanya adalah permintaan POST.
- Content-Type. Pemasok modern biasanya mengirim JSON.
- User-Agent. Bermanfaat untuk debugging, tapi tidak cukup untuk mempercayai.
- Header tanda tangan. Mengandung pengecekan autentikasi pemasok.
- Header timestamp. Digunakan untuk menolak permintaan yang sudah kadaluarsa atau ulang.
Mengapa bentuk tubuh yang penting
code Anda biasanya tidak peduli dengan setiap bidang. Dia peduli dengan jenis acara, identifikasi acara, dan objek bisnis di dalamnya data. Itulah mengapa pengelola yang baik hanya memproses apa yang dibutuhkan dan merekam yang lain untuk memecahkan masalah.
OpenAPI sekarang menggambarkan pola ini secara langsung. OpenAPI 3.1.0 menambahkan dukungan webhook kelas pertama dengan top-level webhooks objek, di mana setiap webhook dijelaskan seperti Item Jalur tetapi diaktifkan oleh penyedia. Contoh yang paling umum menggunakan newPet webhook dengan post operasi, tubuh permintaan JSON, dan 200 respons untuk menunjukkan penerimaan, seperti yang ditunjukkan dalam contoh OpenAPI webhook.
Jika Anda sedang mendokumentasikan kontrak penerima atau penyedia sendiri, contoh yang kuat lebih berguna daripada prosa skema abstrak. Saya suka menggunakan referensi seperti contoh API SheetMergy Karena mereka membuat jelas bagaimana contoh permintaan, deskripsi bidang, dan respons yang diharapkan saling terkait.
Webhook sederhana pada lapisan transportasi. Banyak kegagalan datang dari kesalahpahaman tentang header, pengkodean tubuh, atau aturan tanda tangan.
Bagaimana Mengamankan Verifikasi Tanda Tangan Webhook
Webhook yang ditandatangani menjawab satu pertanyaan: apakah payload ini berasal dari orang yang tahu rahasia bersama?
Perlu diingat bahwa itu berbeda dari bertanya apakah permintaan itu baru atau apakah Anda telah memprosesnya sebelumnya. Verifikasi tanda tangan adalah pintu gerbang pertama, bukan yang terakhir.

Alur Verifikasi
Alur HMAC biasa terlihat seperti ini:
- Baca tanda tangan dari header penyedia.
- Baca permintaan tubuh mentah secara tepat seperti yang diterima.
- Muat webhook rahasia Anda dari konfigurasi yang aman.
- Rekomputasi HMAC yang diharapkan menggunakan algoritma yang sama.
- Bandingkan tanda tangan yang diterima dan tanda tangan yang dihitung dengan perbandingan yang aman waktu.
- Tolak permintaan jika mereka tidak cocok.
Langkah raw-body itu adalah di mana banyak implementasi yang baik lainnya gagal. Jika framework Anda memparse JSON terlebih dahulu, mereformat spasi putih, atau mengubah detail pengkodean sebelum hashing, tanda tangan yang dihitung Anda tidak akan cocok dengan yang disediakan.
Apa yang harus diperhatikan dalam code yang nyata.
Mistake-mistake yang paling sering saya lihat adalah:
- Menghashing JSON yang diparse. Jangan lakukan
JSON.stringify(req.body)dan harapkan akan cocok. - Menggunakan kesetaraan string normal. Gunakan perbandingan yang aman waktu.
- Memasukkan rahasia secara keras. Simpan mereka di variabel lingkungan atau manajer rahasia.
- Mengandalkan header saja. Header tanda tangan hanya bermakna jika Anda memverifikasinya.
Untuk tim yang memperketat pengelolaan rahasia di antara layanan, panduan Capgo tentang Keamanan API kunci untuk kinerja toko aplikasi Relevant karena disiplin yang sama berlaku di sini. Rotasi rahasia, akses yang terbatas, dan menghindari kebocoran di log semua penting untuk penerima webhook juga.
Contoh verifikasi umum
const crypto = require('crypto');
function verifySignature(rawBody, receivedSignature, secret) {
const expected = crypto
.createHmac('sha256', secret)
.update(rawBody)
.digest('hex');
const a = Buffer.from(receivedSignature, 'utf8');
const b = Buffer.from(expected, 'utf8');
if (a.length !== b.length) return false;
return crypto.timingSafeEqual(a, b);
}
Ini sengaja umum. Pemasok nyata sering memperluas tanda tangan, menggabungkan timestamp ke dalam konten yang ditandatangani, atau mengkodekan digest secara berbeda. Aturan tetap sama. Ikuti format tanda tangan pemasok secara tepat, dan selalu verifikasi terhadap payload mentah.
Menghalangi Serangan Ulang
Webhook yang ditandatangani masih berbahaya jika sampai beberapa jam kemudian dan handler Anda menganggapnya sebagai baru. Hal itu lebih sering terjadi daripada tim yang diharapkan. Proksi mencatat lalu lintas, isi pesan permintaan bocor ke tempat yang salah, atau pemasok mengulangi setelah gagal jaringan dan endpoint Anda memproses event yang sama dua kali.

Verifikasi tanda tangan menjawab satu pertanyaan: apakah pengirim menciptakan payload ini dengan rahasia bersama? Perlindungan ulang menjawab pertanyaan yang berbeda: apakah permintaan ini masih boleh diterima sekarang? Penerima produksi membutuhkan kedua-duanya.
Kontrol minimum yang sebenarnya penting
Pencegahan ulang yang efektif dimulai dengan timestamp yang ditandatangani. Pemberi mencantumkan timestamp di dalam header atau di dalam pesan yang ditandatangani, dan penerima Anda menolak permintaan yang jatuh di luar jendela toleransi kecil.
Alur tersebut harus terlihat seperti ini:
- Baca timestamp dari lokasi yang ditentukan oleh pemberiJangan menebak nama header.
- Tafsirnya sebagai bilangan bulat atau tanggal yang diformat RFC,berdasarkan spesifikasi pemberi.
- Bandingkan dengan jam server Anda.
- Tolak permintaan yang terlalu tua atau terlalu jauh di masa depan.
- Verifikasi timestamp sebagai bagian dari skema tanda tangan ketika pemberi mendukungnya.
Poin terakhir itu penting. Jika timestamp tidak tertutup oleh tanda tangan, seorang penyerang dapat mengganti timestamp segar dan memulai kembali tubuh asli.
Apa yang harus dipilih untuk jendela toleransi
Lima menit adalah default umum. Ini cukup singkat untuk mengurangi jendela serangan, tetapi cukup lama untuk bertahan terhadap perbedaan jam kecil dan delay jaringan normal.
Ada perpaduan di sini. Jendela 30 detik terdengar lebih aman, tetapi lebih sering gagal dalam sistem nyata, terutama ketika ulang, antrian, atau ketidaksesuaian regional terlibat. Jendela 30 menit lebih mudah dioperasikan, tetapi memberikan penyerang waktu yang lebih lama jika permintaan yang ditandatangani terbuka.
Pertahanan ulang bukan hanya pengecekan timestamp
Validasi timestamp menghalangi permintaan kuno. Namun, tidak menghentikan pengolahan duplikat di dalam jendela yang valid. Jika event yang ditandatangani yang sama disampaikan dua kali dalam jendela itu, aplikasi Anda masih perlu mengenali itu.
Gunakan lapisan kedua:
- Ikut track ID event atau ID pengiriman dalam penyimpanan yang singkat seperti Redis.
- Tangani handler sebagai idempoten sehingga pengiriman yang sama tidak menciptakan pesanan duplikat, email, atau aksi tagihan.
- Log permintaan kuno yang ditolak With alasan kode, tapi tidak pernah log rahasia atau muatan sensitif penuh.
- Kembalikan respons cepat Setelah validasi dan kerja antrian berat di tempat lain.
Teams that already think about expiry windows and revocation will recognize the pattern. Capgo’s guide to Petunjuk Capacitor untuk pola revokasi token di aplikasi Capacitor Mengulas ide operasional yang sama. Kredensial atau permintaan yang valid sekali tidak boleh dipercaya selamanya.
Yang ditandatangani dan kadaluarsa masih tidak aman.
Membangun Penerima Webhook di Node.js
Node dengan Express masih cara tercepat untuk mendapatkan penerima serius online, tapi ada satu perangkap yang lebih penting dari perangkap lainnya. Anda memerlukan akses ke tubuh mentah sebelum Express mengubahnya menjadi objek.

Contoh Express yang berpikir produksi
const express = require('express');
const crypto = require('crypto');
const app = express();
const PORT = process.env.PORT || 3000;
const WEBHOOK_SECRET = process.env.WEBHOOK_SECRET;
// Capture raw body for signature verification
app.use(
express.json({
verify: (req, res, buf) => {
req.rawBody = buf;
},
})
);
function safeEqual(a, b) {
const aBuf = Buffer.from(a, 'utf8');
const bBuf = Buffer.from(b, 'utf8');
if (aBuf.length !== bBuf.length) return false;
return crypto.timingSafeEqual(aBuf, bBuf);
}
function verifySignature(rawBody, secret, receivedSignature) {
const expected = crypto
.createHmac('sha256', secret)
.update(rawBody)
.digest('hex');
return safeEqual(expected, receivedSignature);
}
function isFresh(timestampHeader, toleranceSeconds = 300) {
const timestamp = Number(timestampHeader);
if (!Number.isFinite(timestamp)) return false;
const now = Math.floor(Date.now() / 1000);
return Math.abs(now - timestamp) <= toleranceSeconds;
}
app.post('/webhooks/example', async (req, res) => {
const signature = req.get('x-webhook-signature');
const timestamp = req.get('x-webhook-timestamp');
if (!WEBHOOK_SECRET) {
return res.status(500).send('Webhook secret is not configured');
}
if (!signature || !timestamp) {
return res.status(400).send('Missing required security headers');
}
if (!isFresh(timestamp)) {
return res.status(401).send('Stale webhook');
}
const valid = verifySignature(req.rawBody, WEBHOOK_SECRET, signature);
if (!valid) {
return res.status(401).send('Invalid signature');
}
// Acknowledge quickly
res.status(200).send('OK');
// Process after acknowledgement
try {
const event = req.body;
console.log('Accepted event:', event.event, event.id);
// enqueueJob(event)
} catch (err) {
console.error('Post-ack processing failed:', err);
}
});
app.listen(PORT, () => {
console.log(`Webhook receiver listening on ${PORT}`);
});
Mengapa struktur ini tetap kokoh
Apa yang dimaksudkan di sini adalah beberapa pilihan:
- Pengambilan tubuh asli terjadi di middleware. Ini mempertahankan byte asli untuk hashing.
- Timestamp dicek sebelum logika bisnis. Tidak ada gunanya melakukan pekerjaan untuk lalu lintas yang sudah kadaluarsa.
- Rute kembali
200cepat. Pekerjaan yang berlangsung lama harus dimasukkan ke dalam antrian atau tugas latar belakang. - Pengolahan setelah konfirmasi diisolasi. Bahkan jika logika downstream gagal, jalur penerima tetap kecil.
Rahasia adalah titik lemah dalam banyak implementasi webhook. Jangan simpan mereka di sumber, jangan tempel mereka ke fixture uji, dan jangan ulangi mereka di log. Jika Anda membutuhkan proses yang lebih luas seputar rotasi dan pengelolaan CI, panduan Capgo untuk mengelola rahasia di pipa CI/CD Rahasia adalah titik lemah dalam banyak implementasi webhook. Jangan simpan mereka di sumber, jangan tempel mereka ke fixture uji, dan jangan ulangi mereka di log. Jika Anda membutuhkan proses yang lebih luas seputar rotasi dan pengelolaan CI, panduan __CAPGO_KEEP_0__ untuk mengelola rahasia di pipa CI/CD menutupi sisi operasional dengan baik.
Jika Anda ingin melihat bagian-bagian yang bergerak dalam aksi, maka walkthrough singkat ini dapat membantu:
Apa yang saya ubah untuk sistem yang berjalan secara langsung
Untuk integrasi penyedia yang nyata, saya akan menambahkan deduplikasi ID event di penyimpanan yang berkelanjutan, log struktur dengan ID permintaan, dan antrian di belakang jalur pengakuan. Saya juga akan menghindari endpoint umum yang dapat digunakan oleh penyedia yang berbeda-beda dengan format tanda tangan yang berbeda. Penggunaan handler yang terpisah lebih mudah untuk dipahami dan lebih sulit untuk rusak.
Membangun Penerima Webhook dengan Python
Flask adalah pilihan yang baik untuk contoh web hook yang bersih karena penanganan permintaan yang eksplisit dan Python memiliki library standar yang sudah memberikan apa yang Anda butuhkan untuk HMAC.
Hal utama yang perlu diingat adalah sama seperti di Node. Verifikasi terhadap byte permintaan asli, bukan dictionary JSON yang telah diparsing.
Contoh Flask dengan pengecekan tanda tangan dan timestamp
import os
import time
import hmac
import hashlib
from flask import Flask, request, jsonify
app = Flask(__name__)
WEBHOOK_SECRET = os.environ.get("WEBHOOK_SECRET", "")
def is_fresh(timestamp_header, tolerance_seconds=300):
try:
timestamp = int(timestamp_header)
except (TypeError, ValueError):
return False
now = int(time.time())
return abs(now - timestamp) <= tolerance_seconds
def verify_signature(raw_body, secret, received_signature):
expected = hmac.new(
secret.encode("utf-8"),
raw_body,
hashlib.sha256
).hexdigest()
return hmac.compare_digest(expected, received_signature)
@app.route("/webhooks/example", methods=["POST"])
def webhook():
if not WEBHOOK_SECRET:
return "Webhook secret is not configured", 500
signature = request.headers.get("X-Webhook-Signature")
timestamp = request.headers.get("X-Webhook-Timestamp")
if not signature or not timestamp:
return "Missing required security headers", 400
if not is_fresh(timestamp):
return "Stale webhook", 401
raw_body = request.get_data()
if not verify_signature(raw_body, WEBHOOK_SECRET, signature):
return "Invalid signature", 401
payload = request.get_json(silent=True) or {}
# Acknowledge receipt
response = jsonify({"status": "ok"})
# In production, queue payload here instead of heavy sync work
print("Accepted event:", payload.get("event"), payload.get("id"))
return response, 200
if __name__ == "__main__":
app.run(port=5000, debug=True)
Detail Flask yang spesifik yang berpengaruh
request.get_data() ini adalah panggilan utama. Ini memberikan Anda byte asli dari tubuh. Jika Anda langsung melompat ke request.json, Anda telah melangkah ke garis yang tidak tepat di mana kesalahan tanda tangan menjadi bingung.
Catatan implementasi beberapa hal:
- Gunakan
hmac.compare_digestsebaliknya dari kesetaraan biasa. - Tangani header yang hilang sebagai kegagalan klien dan tolak awal.
- Gunakan
silent=Trueuntuk parsing JSON jika Anda ingin mengontrol pengelolaan kesalahan daripada membiarkan Flask menerbitkan. - Tinggalkan jalur tipis. Enqueue pekerjaan jika payload memicu apa pun yang mahal.
Jangan debug kesalahan tanda tangan dengan mengurangi pengecekan keamanan. Debug mereka dengan mencetak secara tepat apa saja byte yang Anda hash dan secara tepat apa saja format yang penyedia diharapkan.
Dimana tim biasanya terjebak
Gagal umumnya terjadi ketika melakukan pengujian dengan tubuh JSON yang dibangun tangan, kemudian beralih ke penyedia nyata dan menemukan tanda tangan tidak lagi cocok. Biasanya berarti salah satu dari tiga hal: penyedia menandatangani amplop yang timestamped, tanda tangan dikodekan berbeda dari yang Anda asumsikan, atau middleware mengubah tubuh sebelum verifikasi.
Ketika itu terjadi, berhenti mengubah crypto code secara acak. Tangkap header mentah dan tubuh mentah, reproduksi hash dalam skrip terisolasi kecil, dan hanya kemudian masukkan kembali ke dalam jalur Flask.
Membangun Penerima Webhook di Go
Go adalah pilihan yang bagus untuk penerima webhook karena library standar sudah cukup. Anda tidak memerlukan framework untuk mendapatkan handler kecil dan dapat diandalkan, dan code mudah untuk menjaganya.
Satu hal yang perlu diwaspadai adalah pengelolaan tubuh. r.Body adalah aliran. Baca sekali, hash byte yang Anda dapat, dan kemudian unmarshalling dari byte yang sama.
Contoh library standar
package main
import (
"crypto/hmac"
"crypto/sha256"
"crypto/subtle"
"encoding/hex"
"encoding/json"
"io"
"log"
"net/http"
"os"
"strconv"
"time"
)
type WebhookPayload struct {
Event string `json:"event"`
ID string `json:"id"`
Data json.RawMessage `json:"data"`
}
func isFresh(timestampHeader string, toleranceSeconds int64) bool {
ts, err := strconv.ParseInt(timestampHeader, 10, 64)
if err != nil {
return false
}
now := time.Now().Unix()
diff := now - ts
if diff < 0 {
diff = -diff
}
return diff <= toleranceSeconds
}
func verifySignature(rawBody []byte, secret string, received string) bool {
mac := hmac.New(sha256.New, []byte(secret))
mac.Write(rawBody)
expected := hex.EncodeToString(mac.Sum(nil))
if len(expected) != len(received) {
return false
}
return subtle.ConstantTimeCompare([]byte(expected), []byte(received)) == 1
}
func webhookHandler(secret string) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
return
}
signature := r.Header.Get("X-Webhook-Signature")
timestamp := r.Header.Get("X-Webhook-Timestamp")
if signature == "" || timestamp == "" {
http.Error(w, "missing required security headers", http.StatusBadRequest)
return
}
if !isFresh(timestamp, 300) {
http.Error(w, "stale webhook", http.StatusUnauthorized)
return
}
rawBody, err := io.ReadAll(r.Body)
if err != nil {
http.Error(w, "failed to read body", http.StatusBadRequest)
return
}
if !verifySignature(rawBody, secret, signature) {
http.Error(w, "invalid signature", http.StatusUnauthorized)
return
}
var payload WebhookPayload
if err := json.Unmarshal(rawBody, &payload); err != nil {
http.Error(w, "invalid json", http.StatusBadRequest)
return
}
w.WriteHeader(http.StatusOK)
w.Write([]byte("OK"))
log.Printf("accepted event=%s id=%s", payload.Event, payload.ID)
}
}
func main() {
secret := os.Getenv("WEBHOOK_SECRET")
if secret == "" {
log.Fatal("WEBHOOK_SECRET is not set")
}
http.HandleFunc("/webhooks/example", webhookHandler(secret))
log.Println("listening on :8080")
log.Fatal(http.ListenAndServe(":8080", nil))
}
Mengapa Go terasa solid di sini
Beberapa keuntungan yang menonjol adalah:
- Handler eksplisit. Tidak ada sihir middleware tersembunyi.
- Penggunaan tipe membantu di tepi. Parsing header, konversi tanggal, dan decoding JSON semua gagal dengan jelas.
- The crypto package standar biasanya sudah cukup. Tidak ada ketergantungan tambahan untuk verifikasi HMAC dasar.
Catatan Operasional
Jika volume webhook tumbuh, model konkurensi Go memberikan ruang untuk membagi pekerjaan latar belakang tanpa mengubah pintu masuk HTTP Anda. Bahkan saat itu, tetaplah menjaga penerimaan sempit. Terima, validasi, konfirmasi, lalu tukar.
The webhook handler Go yang kuat biasanya tetap sederhana. Mereka tidak mencampur verifikasi transportasi dengan logika bisnis, dan mereka tidak melakukan pekerjaan basis data berat sebelum respons dikembalikan.
Teknik Debugging yang Paling Penting
Bug webhook biasanya muncul sebagai pesan dukungan, bukan traceback. Pemasok mengatakan mereka telah mengirimkan event. Endpoint Anda mengatakan tidak ada yang mencapai aplikasi, atau verifikasi tanda tangan gagal pada permintaan yang terlihat valid pada pandangan pertama. Pada titik itu, debugging adalah tentang merekonstruksi pertukaran HTTP yang tepat, byte per byte, dan membuktikan di mana itu gagal.

Kit Debugging yang Praktis
Mulai dengan format kabel.
Jika verifikasi tanda tangan gagal, tangkap permintaan tubuh mentah secara tepat seperti yang diterima, bersama dengan header yang digunakan untuk verifikasi. Dalam prakteknya, bug seringkali sederhana. Framework memparse JSON sebelum hashing, proxy mengubah encoding, atau ulang tes melewatkan timestamp header asli. Mencetak objek yang diparse tidak cukup. Anda membutuhkan byte asli dan input verifikasi.
Ini adalah alat-alat yang membantu mengisolasi masalah dengan cepat:
- Pengiriman permintaan mentah. Catat header, jenis konten, panjang konten, dan tubuh yang tidak dimodifikasi selama penyelidikan.
- Endpoint Inspeksi Permintaan. Layanan seperti
webhook.sitemembantu memastikan apa yang dikirimkan pengirim. - Tunneling Lokal.
ngrokdan alat lainnya memungkinkan Anda untuk menguji terhadap penerima lokal sambil mempertahankan penyedia dalam loop. - Replay Manual. Rekonstruksi permintaan dengan
curlatau Postman menggunakan tubuh dan header yang sama. Itu adalah cara tercepat untuk memastikan apakah code atau payload penyedia adalah masalah. - Log Pengiriman Penyedia. Dashboard pengirim sering kali mencakup kode respons, riwayat ulang, dan identifikasi permintaan yang dapat Anda sesuaikan dengan log Anda.
Polanya sangat penting. Kerja dari luar ke dalam. Pertama-tama, verifikasi apakah penyedia mengirimkan apa yang Anda harapkan. Kemudian verifikasi apakah server Anda menerima byte yang sama. Kemudian verifikasi apakah code menghash byte yang sama dengan aturan rahasia dan timestamp yang sama.
Logging yang sebenarnya membantu
Log webhook yang baik harus menjawab tiga pertanyaan dalam satu pencarian:
| Pertanyaan | Field log yang berguna |
|---|---|
| Apakah permintaan sampai? | rute, metode, received_at |
| Mengapa ditolak? | missing_header, stale_timestamp, signature_failed |
| Apakah saya bisa menghubungkannya lagi nanti? | event_id, provider_request_id |
Field keempat membantu dalam sistem nyata. Tambahkan field lokal request_id Dibuat oleh penerima Anda sehingga Anda dapat mengikuti permintaan melalui log aplikasi, antrian, dan pekerja log.
Pilihlah apa yang ingin disimpan. Tidak pernah log rahasia. Hindari membuang payload produksi penuh jika mereka termasuk data pelanggan, token akses, atau detail tagihan. Pola yang lebih aman adalah log metadata plus hash tubuh singkat. Itu masih memungkinkan Anda membandingkan ulang dan memastikan apakah dua pengiriman identik.
Reproduksi gagal dengan input asli
Ini adalah bagian tutorial dasar yang tidak disinggung. Jika Anda tidak dapat merekam kembali permintaan gagal secara tepat, Anda hanya menebak.
Simpan webhook gagal sebagai:
- byte byte tubuh asli
- semua header terkait tanda tangan
- timestamp permintaan
- jenis konten
- ID permintaan penyedia
Replaylah kembali melawan endpoint pengujian. Jika replay berhasil, bandingkan apa yang berubah dalam transit. Penyebab umum termasuk middleware yang memnormalisasi tubuh permintaan, kesalahan pengkodean karakter, dan load balancer yang menghapus atau menulis ulang header. Saya juga pernah melihat gagal karena tim menyalin payload dari tampilan dashboard yang diprint kecil-kecilan daripada tubuh permintaan asli. Perbedaan whitespace saja sudah cukup untuk mematahkan verifikasi HMAC.
Untuk troubleshooting transportasi dan rilis lebih luas, disiplin debugging yang sama muncul dalam panduan Capgo alat-alat untuk debugging pembaruan OTA di Capacitor. Pelajaran yang sama, transportasi yang berbeda. Tangkap jalur permintaan yang sebenarnya sebelum mengubah aplikasi code
Jika verifikasi tanda tangan gagal, inspect byte-byte yang asli, header-header yang tepat yang digunakan dalam verifikasi, dan nilai timestamp sebelum menyentuh kriptografi code
Daftar Periksa untuk Webhook yang Siap Produksi
Penerima biasanya terlihat baik di tahap staging hingga ada badai ulang permintaan, payload yang rusak, atau kesalahan tanda tangan pada pukul 2 pagi. Barikade produksi lebih tinggi. Penerima harus menolak permintaan palsu, menerima ulang permintaan yang sah, dan memberikan signal yang cukup kepada operator untuk debug gagal tanpa mengungkapkan data sensitif.
Pemeriksaan Keamanan dan Korrectif
- Verifikasi setiap tanda tangan permintaan. URL endpoint mengeluarkan. URL uji coba dibagikan di obrolan. Verifikasi tanda tangan adalah kontrol yang memberitahu Anda bahwa pengirim tahu rahasia yang dibagikan.
- Tolak permintaan lama. Tanda tangan yang sah pada payload lama masih dapat direplay. Tetapkan toleransi timestamp yang sesuai dengan model ulang permintaan penyedia.
- Hash badan asli, bukan JSON yang diparsing. Middleware dapat mengurutkan kunci, mengatur whitespace, atau mengubah encoding. Verifikasi harus berjalan terhadap byte-byte yang tepat yang datang.
- Simpan rahasia di luar code. Variabel lingkungan adalah dasar. Manajer rahasia lebih baik jika Anda memutar kredit secara teratur atau menjalankan di beberapa lingkungan.
- Gagal tutup pada kesalahan autentikasi. Jika header tanda tangan hilang, rusak, atau menggunakan skema yang tidak terduga, tolak permintaan dan catat alasan.
Pemeriksaan keandalan
- Konfirmasi cepat. Biasanya penyedia menganggap setiap 2xx sebagai kesuksesan, jadi validasi permintaan, simpan apa yang Anda butuhkan, dan pindahkan pekerjaan yang lambat ke antrian atau pekerja.
- Buat handler idempoten. Acara yang sama mungkin datang lebih dari sekali. Pindahkan efek sampingan ke ID acara, ID pengiriman, atau identifikasi penyedia stabil lainnya.
- Kembalikan kode kesalahan yang dapat diprediksi. Gunakan
400untuk input yang rusak,401atau403untuk verifikasi gagal, dan5xxhanya ketika masalah sistem Anda. Hal ini membuat perilaku ulang penyedia lebih mudah dipahami. - Setel batasan sebelum memproses. Batasi ukuran permintaan Cap, jenis konten, dan jumlah header awal. Hal ini mencegah endpoint webhook menjadi lubang pengolahan umum.
- Tetapkan kontrak sempit. Terima hanya bidang dan jenis acara yang Anda dukung. Pemrosesan longgar terasa nyaman pada awalnya dan menjadi mahal selama penyedia API berubah.
Pengecekan observabilitas
Operasi webhook yang baik terlihat membosankan. Tim dapat menjawab tiga pertanyaan dengan cepat: Apakah kita menerima? Apakah kita memverifikasi? Apakah proses downstream berhasil?
Gunakan standar:
- Track penerimaan, verifikasi, dan pengolahan sebagai hasil yang terpisah.
- Log ID permintaan, ID acara, status tanda tangan, dan pergeseran waktu.
- Pantau delay antrian, latensi pengolah, dan volume ulang.
- Tetapkan jalur ulang aman untuk alur kerja staging atau redelivery.
- Peringatkan perubahan pola, seperti lonjakan gagal tandatangan atau pengiriman duplikat.
Capgo adalah contoh yang berguna dari titik operasional yang lebih luas. Ini termasuk alat sekitar pengiriman rilis dan observabilitas dalam alur kerja pembaruan, serta bagian dari ekosistemnya juga menyentuh alur terkait webhook. Pelajaran ini sangat praktis. Sistem pengiriman membutuhkan visibilitas dari penerimaan hingga selesai.
Jika sebuah tim menutupi periksaan di atas, penerima webhook biasanya dalam kondisi baik untuk produksi. Jika ada item yang hilang, celah tersebut cenderung muncul selama insiden, bukan selama demo.
Frequently Asked Questions Tentang Webhooks
Apa status code yang harus saya kembalikan?
Kembalikan 2xx ketika Anda telah menerima webhook. Jika validasi gagal, kembalikan kesalahan klien atau autentikasi yang sesuai dengan kegagalan, seperti 400 untuk input yang rusak atau 401 untuk data autentikasi yang tidak valid. Pastikan logika tersebut konsisten sehingga dashboard penyedia lebih mudah dipahami.
Apakah saya harus memproses webhook secara sinkron?
Biasanya tidak. Validasi dulu, lalu terima dan kemudian push pekerjaan sebenarnya ke antrian atau pekerja latar belakang. Hal ini menjaga jalur pengiriman tetap cepat dan mengurangi ulang coba yang disebabkan oleh proses bawahannya yang lambat.
Bagaimana cara saya mengatasi ulang coba?
Anggaplah mereka akan terjadi. Bangun ketahanan idempotensi pada handler sehingga menerima event yang sama lagi tidak akan menimbulkan efek sampingan yang sama. ID event atau ID pengiriman penyedia biasanya digunakan sebagai acuan.
Apa jika event datang dalam urutan yang salah?
Desain handler untuk toleran terhadap urutan ketika memungkinkan. Jika proses bisnis memerlukan urutan, simpan cukup banyak informasi untuk mendeteksi transisi yang ketinggalan waktu daripada menganggap urutan pengiriman menunjukkan urutan event.
Bagaimana saya mengatasi perubahan versi webhook?
Versi logika handler secara sengaja. Simpan parsing penyedia yang spesifik terisolasi, hindari menyebarkan asumsi payload melalui kodebase, dan tambahkan tes dengan contoh yang sebenarnya sebelum meluncurkan dukungan untuk format baru.
Jika tim Anda mengirimkan Capacitor atau aplikasi Electron, Capgo adalah hal yang perlu diketahui karena alasan yang terkait. Ini memberikan tim cara yang terkendali untuk mengirimkan pembaruan web yang ditandatangani, mengamati perilaku pengiriman, dan memulihkan dari insiden tanpa menunggu ulasan toko aplikasi, yang sesuai dengan insting insinyur yang sama di balik desain webhook yang solid: validasi input, jaga jalur pengiriman terlihat, dan lakukan pemulihan dengan cepat.