شرح Webhooks: الحمولات الموقعة واستراتيجيات إعادة المحاولة
لقد قمت للتو بدمج بوابة دفع أو خدمة CI/CD، والآن تحتاج إلى استقبال الأحداث في الوقت الفعلي. قمت بإعداد نقطة نهاية (endpoint)، ولكن سرعان ما تواجه سؤالين حاسمين: كيف تضمن أن الطلب جاء فعلاً من الخدمة؟ وماذا يحدث إذا كان خادمك متوقفاً عند إطلاق حدث ما؟ يجيب هذا المقال على كليهما من خلال شرح الحمولات الموقعة واستراتيجيات إعادة المحاولة—العمود الفقري لـ webhooks الموثوقة.
ما هي Webhooks؟
Webhooks هي عمليات استدعاء HTTP (callbacks) يحددها المستخدم. عند حدوث حدث في نظام المصدر (مثل commit جديد، أو نجاح عملية دفع)، يُرسل طلب HTTP POST إلى عنوان URL تحدده أنت. على عكس الاستقصاء (polling)، تدفع webhooks البيانات في الوقت الفعلي تقريباً، مما يقلل من زمن التأخير وحمل الخادم. ومع ذلك، يفرض نموذج الدفع هذا تحديات: التحقق من الأصالة والتعامل مع فشل التسليم.
لماذا تُعد الحمولات الموقعة مهمة
يمكن لأي شخص إرسال طلب HTTP إلى نقطة النهاية الخاصة بك. بدون التحقق، يمكن للمهاجمين تزوير الأحداث، مما يؤدي إلى إجراءات غير مصرح بها. تحل الحمولات الموقعة هذه المشكلة من خلال تضمين توقيع تشفيري يُحسب على جسم الطلب باستخدام سر مشترك. يعيد المستقبل حساب التوقيع ويقارنه، مما يضمن أن الحمولة لم يتم التلاعب بها وأنها صادرة من المرسل المتوقع.
كيف تعمل توقيعات HMAC
تستخدم معظم الخدمات HMAC-SHA256. ينشئ المرسل توقيعاً عن طريق تجزئة (hashing) الحمولة باستخدام مفتاح سري ويضمّنه في ترويسة (header) (مثل X-Signature). يفعل المستقبل الشيء نفسه ويقارن باستخدام دالة مقارنة ثابتة الزمن لمنع هجمات التوقيت (timing attacks).
خطوة بخطوة: التحقق من حمولة موقعة
- استخرج التوقيع من الترويسة (مثل
X-Signature). - احصل على جسم الطلب الخام كسلسلة نصية أو buffer—لا تقم بتحليله أولاً، لأن تغييرات التنسيق تكسر التوقيع.
- احسب التوقيع المتوقع باستخدام HMAC-SHA256 مع مفتاحك السري.
- قارن التوقيعات باستخدام دالة مقارنة ثابتة الزمن.
- ارفض الطلب برمز HTTP 401 إذا لم يتطابقا.
إليك مثالاً بلغة Node.js باستخدام Express:
const crypto = require('crypto');
const express = require('express');
const app = express();
app.post('/webhook', express.raw({type: 'application/json'}), (req, res) => {
const signature = req.headers['x-signature'];
const secret = process.env.WEBHOOK_SECRET;
const payload = req.body; // raw buffer
const expected = crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');
if (!crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected))) {
return res.status(401).send('Invalid signature');
}
// Process the event
const event = JSON.parse(payload);
// ... handle event
res.status(200).send('OK');
});
ملاحظة: استخدم دائماً الجسم الخام للتحقق. البرمجيات الوسيطة (middleware) التي تحلل JSON ستغيّر الحمولة، مما يسبب عدم تطابق التوقيع.
تصميم استراتيجية إعادة المحاولة
حتى مع الحمولات الموقعة، يمكن أن تؤدي مشكلات الشبكة أو تعطل الخادم إلى فشل التسليم. تضمن استراتيجية إعادة المحاولة القوية عدم فقدان الأحداث. الاعتبارات الرئيسية:
1. الإقرار بسرعة
استجب بحالة 2xx بمجرد التحقق من التوقيع ووضع الحدث في قائمة الانتظار للمعالجة. هذا يمنع المرسل من انتهاء المهلة وإعادة المحاولة دون داعٍ.
2. الحيادية للتكرار (Idempotency)
قد تسلّم إعادة المحاولات نفس الحدث عدة مرات. استخدم مفتاح idempotency (غالباً ما يُضمّن في الحمولة أو الترويسات) لإزالة التكرار. خزّن معرفات الأحداث المعالجة وتجاهل التكرارات.
3. التراجع الأسي مع التذبذب (Jitter)
إذا أعادت نقطة النهاية خطأً (غير 2xx)، يجب على المرسل إعادة المحاولة بتأخيرات متزايدة. يقلل التراجع الأسي (مثل 1s، 2s، 4s، 8s) من الحمل أثناء الانقطاعات. إضافة تذبذب عشوائي يمنع مشاكل القطيع المتلاطم (thundering herd).
جدول إعادة محاولة نموذجي:
| المحاولة | التأخير |
|---|---|
| 1 | فوري |
| 2 | دقيقة واحدة |
| 3 | 5 دقائق |
| 4 | 30 دقيقة |
| 5 | ساعتان |
4. قائمة الرسائل الميتة (Dead Letter Queue)
بعد الحد الأقصى من المحاولات، انقل الحدث إلى قائمة الرسائل الميتة للفحص اليدوي. هذا يمنع المحاولات اللانهائية وفقدان البيانات.
5. المراقبة والتنبيهات
تتبّع معدلات نجاح التسليم وزمن التأخير وأسباب الفشل. قم بإعداد تنبيهات لارتفاعات حالات الفشل لاكتشاف المشكلات مبكراً.
المزالق الشائعة وأفضل الممارسات
- تحقق دائماً من التوقيعات—لا تثق أبداً بالبيانات الواردة بشكل أعمى.
- استخدم HTTPS لحماية الحمولات أثناء النقل.
- قم بتدوير الأسرار دورياً وادعم أسراراً متعددة نشطة أثناء التدوير.
- سجّل أحداث webhook (مع حجب البيانات الحساسة) لأغراض التصحيح.
- اختبر باستخدام حمولات نموذجية باستخدام أدوات تحاكي تسليم webhook.
الأسئلة الشائعة
ما هي الحمولة الموقعة في webhooks؟
تتضمن الحمولة الموقعة توقيعاً تشفيرياً (عادةً HMAC) يسمح للمستقبل بالتحقق من أصالة الطلب وسلامته.
كم مرة يجب إعادة محاولة webhook؟
لا يوجد رقم ثابت؛ تتراوح الممارسات الشائعة بين 3 و10 محاولات مع تراجع أسي. بعد ذلك، غالباً ما تُرسل الأحداث إلى قائمة الرسائل الميتة.
هل يمكنني استخدام webhooks بدون توقيعات؟
من الممكن لكنه غير مُستحسن بشدة. بدون توقيعات، تكون نقطة النهاية الخاصة بك عرضة للطلبات المزورة وانتهاكات البيانات.
هل أنت مستعد لاختبار حمولات webhook الخاصة بك؟ استخدم JSON Formatter الخاص بنا لفحص والتحقق من حمولات JSON بسرعة.