Anda memiliki layanan yang perlu bereaksi ketika sesuatu terjadi di tempat lain. Pembayaran terkonfirmasi. Rekaman pelanggan berubah. Repositori menerima push. Anda bisa memantau layanan 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, dan mengembalikan, dan menganggapnya selesai. Versi tersebut berfungsi dengan baik hingga seseorang mengirimkan permintaan palsu, memulai ulang permintaan yang valid, atau handler Anda rusak karena kerangka kerja memproses tubuh sebelum verifikasi tanda tangan. 200Panduan ini mengambil jalur yang akan digunakan di produksi. Contoh-contoh tersebut kecil sehingga dapat dicopy, tetapi mereka termasuk bagian yang penting: pengolahan tubuh mentah, verifikasi HMAC, pengecekan timestamp, pengakuan cepat, dan debugging yang praktis.
Tabel Isi
Mengapa Menggunakan Webhook
- Model mental yang membantu
- Anatomi Permintaan HTTP Webhook
- Bagaimana Membuktikan Tanda Tangan Webhook dengan Aman
- Mengamankan 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 Produksi
- Frequently Asked Questions Tentang Webhook
Apa itu Webhook dan Mengapa Menggunakannya?
Pemberi tagihan Anda menandai tagihan sebagai dibayar pada pukul 02:13. Jika aplikasi Anda mengetahuinya pada pukul 02:14, pelanggan mendapatkan akses segera. Jika aplikasi Anda mengetahuinya 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 istilah praktis, sebuah webhook adalah POST acara yang dikendalikan oleh event dari satu sistem ke sistem lain. Pemberi mendeteksi perubahan, seperti pembayaran, atau aktivitas repositori, dan mengirimkan data acara ke URL yang Anda kendalikan. Ini menghilangkan loop invoice.paid, order.created apa yang baru? push yang terus-menerus yang diciptakan oleh polling dan mengurangi banyak permintaan yang sia-sia.
Gaya ini muncul dalam sistem nyata karena memetakan dengan jelas ke acara bisnis. Stripe mengirimkan hasil pembayaran. GitHub mengirimkan aktivitas repositori. Shopify mengirimkan update pesanan. Bentuknya sederhana, tetapi perilaku produksi tidak. Webhook yang memperbarui uang, akses, atau inventori memerlukan perawatan yang sama seperti endpoint publik API apa pun, terutama setelah retries, duplikat, dan lalu lintas tidak terpercaya masuk ke dalam gambaran.
Model mental yang membantu
Cara yang berguna untuk menggambarkan aliran webhook adalah sebagai empat bagian yang bekerja bersama:
- Sumber sistem. Layanan yang mendeteksi acara.
- Tujuan endpoint. Rute HTTP Anda yang menerima itu.
- Event. Perubahan yang dinamai yang terjadi, seperti
invoice.paidataupush. - Payload. Tubuh permintaan dengan detail yang dibutuhkan oleh code Anda.
Pemberi data mengirim 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 mengakui.
Aturan praktis: Gunakan webhooks untuk pembaruan berdasarkan event. Gunakan polling untuk bacaan yang dijadwalkan, backfills, atau pemberi data yang tidak menawarkan event keluar.
Untuk tim yang membangun sistem yang lebih luas dan otomatisasi alur kerja serta 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 Memiliki konteks yang berguna karena masalah inti muncul di sekitar ulang coba, antrian, observabilitas, dan pengelolaan gagal.
Apa yang berhasil dan apa yang gagal di produksi
Konfigurasi yang dapat bertahan baik biasanya dirancang untuk membosankan. Berlangganan hanya ke event yang Anda butuhkan. Pastikan endpoint Anda terbatas berdasarkan penyedia atau keluarga event. Simpan ID event untuk mencegah pengiriman ulang efek sampingan. Kembalikan respons cepat 2xx setelah permintaan diverifikasi dan diantrekan, kemudian lakukan logika bisnis yang lebih lambat secara asinkron.
Versi yang rapuh mudah dikenali. Satu endpoint umum menangani segalanya. Pengecekan tanda tangan dibatalkan selama pengujian awal dan tidak pernah kembali. Pengolah menulis langsung ke tabel kritis sebelum memeriksa apakah event tersebut autentik atau sudah kadaluarsa. Hal itu berhasil dalam demo dan gagal di bawah badai ulang coba, gangguan penyedia, atau penyerang yang mereplay permintaan lama.
Kompromi itu yang menentukan sisa panduan ini. Versi
hello world
Before writing code, it helps to look at the request as raw HTTP instead of as a framework object. A typical webhook is just an HTTP POST to a public endpoint with headers and a JSON body.
Anatomi Permintaan Webhook HTTP
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"
}
}
Sebelum menulis __CAPGO_KEEP_0__, membantu untuk melihat permintaan sebagai HTTP mentah daripada sebagai objek framework. Webhook biasanya hanya sebuah permintaan HTTP POST ke endpoint publik dengan header dan tubuh JSON.
- Permintaan sederhana mentahBagian pentingnya jelas:
- Content-TypePaling banyak penyedia modern mengirim JSON.
- User-AgentBermanfaat untuk debugging, tapi tidak cukup untuk membangun kepercayaan.
- Kop Surat keamananMengangkut periksa keaslian penyedia.
- Kop WaktuDigunakan untuk menolak permintaan yang sudah ketinggalan atau direplay.
Mengapa bentuk tubuh penting
Biasanya code Anda tidak peduli dengan setiap bidang. Dia peduli dengan jenis event, identifikasi event, dan objek bisnis di dalamnya dataItulah mengapa baik handler hanya memproses apa yang dibutuhkan dan log sisanya untuk troubleshooting.
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 Path Item tetapi diaktifkan oleh penyedia. Contoh yang paling umum menggunakan webhook dengan newPet operasi, tubuh permintaan JSON, dan post respons untuk menunjukkan penerimaan, seperti yang ditunjukkan dalam contoh webhook OpenAPI 200 Jika Anda mendokumentasikan kontrak penerima atau penyedia sendiri, contoh yang kuat lebih bermanfaat daripada prosa skema abstrak. Saya suka menggunakan referensi seperti contoh dokumen __CAPGO_KEEP_0__ SheetMergy karena mereka membuat jelas bagaimana contoh permintaan, deskripsi bidang, dan respons yang diharapkan saling terkait..
Webhook sederhana pada lapisan transportasi. Banyak gagal datang dari kesalahpahaman tentang header, pengkodean tubuh, atau aturan tanda tangan. SheetMergy’s API doc examples Webhook yang ditandatangani menjawab satu pertanyaan: apakah payload ini berasal dari seseorang yang tahu rahasia bersama?
Berbeda dengan bertanya apakah permintaan itu baru atau apakah Anda sudah memprosesnya. Verifikasi tanda tangan adalah pintu gerbang pertama, bukan yang terakhir.
How to Securely Verify Webhook Signatures
A signed webhook answers one question: did this payload come from someone who knows the shared secret?
That’s different from asking whether the request is recent or whether you’ve already processed it.

Alur verifikasi
Alur HMAC biasanya terlihat seperti ini:
- Baca tanda tangan dari header penyedia.
- Baca badan permintaan mentah dengan tepat seperti yang diterima.
- Muat kunci webhook 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 aman waktu.
- Tolak permintaan jika mereka tidak cocok.
Langkah itu badan permintaan mentah adalah di mana banyak implementasi yang baik gagal. Jika kerangka kerja Anda memparse JSON terlebih dahulu, mereformat spasi putih, atau mengubah detail pengkodean sebelum hashing, tanda tangan yang dihitung tidak akan cocok dengan penyedia.
Apa yang perlu diperhatikan dalam code yang nyata
Berikut adalah kesalahan yang paling sering saya lihat:
- Menghashing JSON yang diparsingJangan melakukannya
JSON.stringify(req.body)dan harapkan itu akan cocok. - Menggunakan kesetaraan string normalGunakan perbandingan aman waktu.
- Menggunakan rahasia yang kerasSimpan mereka di variabel lingkungan atau manajer rahasia.
- Mengandalkan header sajaTanda tangan header hanya berarti jika Anda memverifikasinya.
Untuk tim yang memperketat penanganan rahasia di antara layanan, panduan Capgo tentang API kunci keamanan untuk kinerja toko aplikasi hal ini relevan karena disiplin yang sama berlaku di sini. Rotasi rahasia, akses yang terbatas, dan menghindari kebocoran dalam 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 waktu menjadi konten yang ditandatangani, atau mengkodekan digest secara berbeda. Aturan tetap sama. Ikuti format tanda tangan pemasok secara tepat, dan selalu verifikasi terhadap payload mentah.
Melindungi Serangan Ulang
Webhook yang ditandatangani masih berbahaya jika sampai beberapa jam kemudian dan handler Anda menganggapnya sebagai yang baru. Hal itu lebih sering terjadi daripada tim yang diharapkan. Proksi log lalu lintas, isi payload permintaan bocor ke tempat yang salah, atau penyedia ulang 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 yang sama? Perlindungan ulang menjawab pertanyaan yang berbeda: apakah permintaan ini masih diterima sekarang?
Pengecekan minimum yang sebenarnya penting
Perlindungan ulang yang praktis dimulai dengan timestamp yang ditandatangani. Penyedia mencantumkan timestamp di dalam header atau di dalam pesan yang ditandatangani, dan penerima Anda menolak permintaan yang jatuh di luar jendela toleransi yang kecil.
Alur yang harus seperti ini:
- Baca timestamp dari lokasi yang ditentukan penyedia. Jangan menebak nama header.
- Tafsirnya sebagai bilangan bulat atau tanggal berformat RFC, berdasarkan spesifikasi penyedia.
- 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 penyedia mendukungnya.
Poin terakhir itu penting. Jika timestamp tidak tertutup oleh tanda tangan, seorang penyerang dapat mengganti timestamp segar dan memulai ulang tubuh asli. Saya selalu memeriksa format tanda tangan penyedia secara tepat sebelum saya percaya logika timestamp.
Apa yang dipilih untuk jendela toleransi
Lima menit adalah default umum. Ini cukup pendek untuk mengurangi jendela serangan, tetapi cukup lama untuk bertahan melawan perbedaan jam kecil dan keterlambatan jaringan normal.
Ada perbandingan di sini. Jendela 30 detik terdengar lebih aman, tetapi lebih sering gagal dalam sistem nyata, terutama ketika ulang, antrian, atau keterlambatan regional terlibat. Jendela 30 menit lebih mudah dioperasikan, tetapi memberikan penyerang waktu yang lebih lama jika permintaan yang ditandatangani terbuka. Mulai dengan beberapa menit, sinkronkan server Anda dengan NTP, lalu ketatkan hanya jika pola pengiriman penyedia mendukungnya.
Pertahanan ulang bukan hanya cek timestamp
Validasi timestamp menghalangi permintaan yang sudah kadaluarsa. Namun, tidak menghentikan proses pengulangan di dalam jendela yang valid. Jika event yang ditandatangani sama disampaikan dua kali dalam jendela tersebut, aplikasi Anda masih perlu mengenali event tersebut.
Pakailah layer kedua:
- Ikuti ID event atau ID pengiriman di dalam penyimpanan yang berumur pendek seperti Redis.
- Tangani handler sebagai idempoten agar pengiriman yang berulang tidak menciptakan pesanan yang sama, email, atau aksi billing.
- Log permintaan yang sudah kadaluarsa dengan kode alasan, namun tidak pernah logkan rahasia atau payload sensitif yang lengkap.
- Kembalikan respons yang cepat setelah validasi dan kerja berat di tempat lain.
Tim yang sudah berpikir tentang jendela kadaluarsa dan revokasi akan mengenali pola tersebut. Panduan Capgo untuk pola revokasi token di aplikasi Capacitor menutupi gagasan operasional yang sama. Suatu kredit atau permintaan yang valid sekali tidak boleh tetap dipercaya selamanya.
Terdaftar dan kadaluarsa masih tidak aman.
Membangun Penerima Webhook di Node.js
Node dengan Express masih cara termudah untuk mendapatkan penerima serius online, tetapi ada satu perangkap yang lebih penting dari segala perangkap lainnya. Anda memerlukan akses ke tubuh mentah sebelum Express mengubahnya menjadi objek.

Contoh Express yang berorientasi 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
Pilihan-pilihan di sini adalah sengaja:
- Pemangkasan tubuh mentah terjadi di middleware. Itu mempertahankan byte asli untuk hashing.
- Waktu timestamp dicek sebelum logika bisnis. Tidak ada gunanya melakukan pekerjaan untuk lalu lintas kadaluarsa.
- The route kembali mengembalikan
200cepat. Tugas berjalan lama dimasukkan ke dalam antrian atau tugas latar belakang. - Proses pengolahan setelah konfirmasi diisolasi. Bahkan jika logika hilir 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 cetak mereka di log. Jika Anda membutuhkan proses yang lebih luas seputar rotasi dan pengelolaan CI, panduan Capgo tentang pengelolaan rahasia di pipeline CI/CD menjelaskan sisi operasional dengan baik.
Langkah-langkah singkat membantu jika Anda ingin melihat bagian-bagian yang bergerak secara langsung:
Apa yang saya ubah untuk sistem hidup
Untuk integrasi penyediaan nyata, saya akan menambahkan deduplikasi ID event di penyimpanan persisten, log struktur dengan ID permintaan, dan antrian di belakang jalur konfirmasi. Saya juga akan menghindari endpoint umum yang dapat digunakan jika penyedia yang berbeda menggunakan format tanda tangan yang berbeda. Penggunaan handler yang terpisah lebih mudah untuk dipahami dan lebih sulit untuk rusak.
Pembangunan Penerima Webhook di Python
Flask cocok untuk contoh hook web yang bersih karena pengolahan permintaan eksplisit dan Python's library standar sudah memberikan apa yang Anda butuhkan untuk HMAC.
Hal utama yang perlu diingat sama seperti di Node. Verifikasi terhadap byte permintaan asli, bukan dictionary JSON yang 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 berpengaruh
request.get_data() adalah panggilan kunci di sini. Ia memberikan Anda byte-byte asli dari tubuh. Jika Anda langsung melompat ke request.json, Anda sudah melewati garis di mana kesalahan tanda tangan menjadi bingung.
Catatan implementasi beberapa hal:
- Pakai
hmac.compare_digestbukalahan dengan kesetaraan biasa. - Tangani kepala yang hilang sebagai gagal klien dan tolak awal.
- Pakai
silent=Trueuntuk parsing JSON jika Anda ingin mengontrol penanganan kesalahan daripada membiarkannya Flask mengangkat. - Tahan rute tipisEnqueue pekerjaan jika payload memicu apa pun yang mahal.
Tidak debug kesalahan tanda tangan dengan menurunkan pengecekan keamanan. Debug mereka dengan mencetak secara tepat apa saja byte yang Anda hash dan secara tepat apa saja format penyedia yang diharapkan.
Dimana tim biasanya terjebak
Jalan kegagalan umum adalah melakukan pengujian dengan tubuh JSON yang dibangun tangan, kemudian beralih ke penyedia sebenarnya 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, hentikan mengubah crypto code secara acak. Tangkap header mentah dan tubuh mentah, reproduksi hash dalam skrip kecil terisolasi, dan baru kemudian masukkan kembali ke dalam rute 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 mempertahankannya.
Satu hal yang perlu diwaspadai adalah penanganan tubuh. r.Body adalah aliran. Baca sekali, hash byte yang Anda dapatkan, dan kemudian unmarshalling dari byte yang sama.
Contoh perpustakaan 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 manfaat yang menonjol adalah:
- Pengolah adalah eksplisit. Tidak ada sihir middleware tersembunyi.
- Pengaturan tipe membantu di tepi. Parsing header, konversi tanggal, dan dekripsi JSON semua gagal dengan jelas.
- Paket kriptografi standar sudah cukup. Tidak perlu dependensi tambahan untuk verifikasi HMAC dasar.
Catatan operasional
Jika volume webhook tumbuh, model konkurensi Go memberi Anda ruang untuk membagi kerja latar belakang tanpa mengubah titik masuk HTTP Anda. Bahkan saat itu, tetapkan penerima sempit. Terima, validasi, konfirmasi, lalu tukar.
Pengolah webhook Go yang kuat yang pernah saya lihat tetap membosankan. Mereka tidak mencampur verifikasi transportasi dengan logika bisnis, dan mereka tidak melakukan pekerjaan basis data berat sebelum respons kembali.
Teknik Debugging Dasar
Masalah webhook biasanya muncul sebagai pesan dukungan, bukan tumpukan jejak. Pemasok mengatakan mereka telah mengirimkan event. Endpoint Anda mengatakan tidak ada yang mencapai aplikasi, atau verifikasi tanda tangan gagal pada permintaan yang tampaknya valid pada pandangan pertama. Pada titik itu, debugging tentang merekonstruksi pertukaran HTTP yang tepat, byte per byte, dan membuktikan di mana itu rusak.

Kit Debugging Praktis
Mulai dengan format kabel.
Jika pengecekan tanda tangan gagal, tangkap badan permintaan mentah secara tepat seperti yang diterima, bersama dengan header yang digunakan untuk verifikasi. Dalam prakteknya, masalah biasanya membosankan. Framework memparse JSON sebelum hashing, proxy mengubah encoding, atau ulang tayang tes melewatkan timestamp asli header. Mencetak objek yang diparse tidak cukup. Anda membutuhkan byte asli dan input verifikasi.
Ini adalah alat-alat yang membantu mengisolasi masalah cepat:
- Perekaman permintaan mentah. Log header, jenis konten, panjang konten, dan badan yang tidak dimodifikasi selama penyelidikan.
- Endpoint Inspeksi Permintaan. Layanan seperti
webhook.sitemembantu memastikan apa yang dikirimkan oleh pengirim. - Jaringan lokal.
ngrokdan alat-alat serupa memungkinkan Anda untuk menguji terhadap penerima lokal sambil membiarkan penyedia tetap dalam loop. - Replay manual. Rebuild 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 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 waktu dan rahasia yang sama.
Log yang sebenarnya membantu
Log webhook yang baik harus menjawab tiga pertanyaan dalam satu pencarian:
| Pertanyaan | Kolom log yang berguna |
|---|---|
| Apakah permintaan itu sudah sampai? | rute, metode, diterima pada |
| Mengapa permintaan itu ditolak? | header hilang, timestamp kadaluarsa, tanda tangan gagal |
| Apakah saya bisa menghubungkannya kemudian? | id_event, id_permintaan_providder |
Faktor keempat membantu dalam sistem nyata. Tambahkan field lokal request_id dibuat oleh penerima lokal Anda sehingga Anda bisa mengikuti permintaan melalui log aplikasi, antrian, dan log pekerja
Pilihlah dengan hati-hati apa yang disimpan. Tidak pernah log rahasia. Hindari membuang payload produksi lengkap 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 yang dasar tutorial tidak menyentuh. Jika Anda tidak bisa merekam permintaan gagal secara tepat, Anda hanya menebak.
Simpan webhook gagal sebagai:
- byte tubuh asli
- semua header terkait tanda tangan
- timestamp permintaan
- jenis konten
- ID permintaan penyedia
Kemudian ulangiinya terhadap endpoint pengujian. Jika ulangan tersebut berhasil, bandingkan apa yang berubah selama transit. Pemicu umum termasuk middleware yang menyederhanakan tubuh permintaan, kesalahan pengkodean karakter, dan load balancer yang menghilangkan atau menulis ulang header. Saya juga pernah melihat gagalnya disebabkan oleh tim yang menyalin payload dari tampilan dashboard yang telah dipretty-print daripada tubuh permintaan asli. Perbedaan whitespace saja sudah cukup untuk mematahkan verifikasi HMAC.
Untuk rilis yang lebih luas dan troubleshooting transportasi mobile, disiplin debugging yang sama muncul dalam panduan Capgo untuk alat-alat untuk debugging update OTA di CapacitorTransportasi yang berbeda, pelajaran yang sama. Tangkap path permintaan asli sebelum mengubah aplikasi code.
Jika verifikasi tanda tangan gagal, inspect byte tubuh asli, header yang tepat digunakan dalam verifikasi, dan nilai timestamp sebelum menyentuh kriptografi code.
Daftar Periksa untuk Webhook yang Siap Produksi
Pengolah webhook biasanya terlihat baik di pengujian sampai dengan badai ulangan pertama, payload yang rusak, atau kesalahan tanda tangan pada pukul 2 pagi. Bar produksi lebih tinggi. Penerima harus menolak permintaan palsu, menerima ulangan yang sah, dan memberikan signal yang cukup kepada operator untuk debug gagalnya tanpa mengungkapkan data sensitif.
Pemeriksaan keamanan dan korektif
- Verifikasi setiap tanda tangan permintaan. URL endpoint terbuka. URL uji dipublikasikan di obrolan. Verifikasi tanda tangan adalah kontrol yang memberitahu Anda bahwa pengirim mengetahui rahasia yang disepakati.
- Tolak permintaan lama. Tanda tangan yang valid pada payload lama masih dapat direplay. Tetapkan toleransi timestamp yang sesuai dengan model ulang permintaan penyedia.
- Geser tubuh mentah, bukan JSON yang diparsing. Middleware dapat mengurutkan kunci, normalisasi spasi, atau mengubah encoding. Verifikasi harus berjalan terhadap byte yang tepat yang datang.
- Tetapkan rahasia tanda tangan di luar code. Variabel lingkungan adalah dasar. Manajer rahasia lebih baik jika Anda memutar kredential secara berkala atau menjalankan di beberapa lingkungan.
- Kosongkan pada kesalahan autentikasi. Jika header tanda tangan hilang, rusak, atau menggunakan skema yang tidak terduga, tolak permintaan dan catat alasan.
Pemeriksaan keandalan
- Konfirmasi cepat. Pemasok biasanya 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 identifier stabil pemasok lainnya.
- Kembalikan kode error yang dapat diprediksi. Gunakan
400untuk masukan yang rusak,401atau403untuk verifikasi gagal, dan5xxhanya ketika sistem Anda adalah masalah. Ini membuat perilaku ulang pemasok lebih mudah dipahami. - Setel batasan sebelum memproses. Batasi ukuran permintaan, jenis konten, dan jumlah header awal. Ini mencegah endpoint webhook menjadi lubang pengolahan umum.
- Tetapkan kontrak sempit. Hanya terima bidang dan jenis acara yang Anda dukung. Pemrosesan longgar terasa nyaman pada awalnya dan menjadi mahal selama perubahan penyedia API.
Pengecekan observabilitas
Operasi webhook yang baik terlihat membosankan. Tim dapat menjawab tiga pertanyaan dengan cepat: Apakah kita menerima itu? Apakah kita memverifikasi itu? Apakah proses downstream berhasil?
Gunakan standar:
- Tandai penerimaan, verifikasi, dan pengolahan sebagai hasil yang terpisah.
- Log ID permintaan, ID acara, status tanda tangan, dan pergeseran waktu.
- Ukurlah delay antrian, latensi pengolah, dan volume ulang coba.
- Tetapkan jalur ulang main yang aman untuk alur kerja staging atau redelivery.
- Peringatkan pada perubahan polaseperti lonjakan pada gagal tanda tangan atau pengiriman duplikat.
Capgo adalah contoh operasional yang lebih luas. Ini termasuk alat sekitar pengiriman rilis dan observabilitas dalam alur kerja pembaruan, serta bagian dari ekosistemnya juga menyentuh alur kerja webhook terkait. Pelajaran ini sangat praktis. Sistem pengiriman membutuhkan visibilitas dari penerimaan hingga selesai.
If sebuah tim telah menutup cek-cek 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 sebuah 2xx ketika Anda telah menerima webhook. Jika validasi gagal, kembalikan sebuah kesalahan klien atau autentikasi yang sesuai dengan kegagalan, seperti 400 untuk input yang tidak berbentuk atau 401 untuk data autentikasi yang tidak valid. Jaga logika tersebut konsisten sehingga dashboard penyedia lebih mudah diinterpretasikan.
Apakah saya harus memproses webhook secara sinkron?
Biasanya tidak. Validasikan, akui, lalu pindahkan pekerjaan yang sebenarnya ke antrian atau pekerjaan latar belakang. Hal ini menjaga jalur pengiriman cepat dan mengurangi ulang coba yang disebabkan oleh proses bawahannya yang lambat.
Bagaimana saya harus menghandle ulang coba?
Anggap mereka akan terjadi. Bangun ketidakbergantungan ke dalam handler Anda sehingga menerima event yang sama lagi tidak akan menghasilkan efek sampingan yang berulang. ID event atau ID pengiriman penyedia biasanya adalah anker yang biasa digunakan untuk itu.
Apa jika event datang dalam urutan yang salah?
Rancang handler untuk toleran terhadap urutan ketika memungkinkan. Jika proses bisnis memerlukan urutan, simpan cukup state untuk mendeteksi transisi ketinggalan daripada asumsi urutan pengiriman merepresentasikan urutan event.
Bagaimana saya menghadapi perubahan versi webhook?
Versi logika handler dengan sengaja. Simpan parsing spesifik penyedia terisolasi, hindari menyebarkan asumsi muatan melalui kodebase, dan tambahkan tes dengan contoh yang sebenarnya sebelum mengeluarkan 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 dikendalikan untuk mengirimkan pembaruan web yang ditandatangani, mengamati perilaku pengiriman, dan mengembalikan dari insiden tanpa menunggu ulasan toko aplikasi, yang sesuai dengan insting insinyur yang sama di balik desain webhook yang solid: validasi input, jaga jalur rilis teramati, dan lakukan pemulihan dengan cepat.