كيف تصمم Webhooks موثوقة؟

Ashley Innocent

Ashley Innocent

13 مارس 2026

كيف تصمم Webhooks موثوقة؟

تلخيص سريع

صمم Webhooks موثوقة باستخدام إعادة المحاولة بأسلوب التراجع الأُسي (5-10 محاولات)، ومفاتيح المعاودة الآمنة، والتحقق من توقيع HMAC، ومهلات 5 ثوانٍ. أعد استجابة 2xx فورًا، وقم بالمعالجة بشكل غير متزامن. تطبق PetstoreAPI الحديثة Webhooks لتحديثات الطلبات، وعمليات تبني الحيوانات الأليفة، وإشعارات الدفع مع إعادة محاولة وأمان كاملين.

مقدمة

ترسل Webhook لإخطار عميل بأن حيوانه الأليف قد تم تبنيه. خادم العميل معطل. يفشل الـ Webhook الخاص بك. هل تعيد المحاولة؟ كم مرة؟ وماذا لو استلم العميل الـ Webhook مرتين وقام بخصم المبلغ من العميل مرتين؟

Webhooks هي استدعاءات HTTP تعيد الأحداث إلى عناوين URL للعملاء. إنها بسيطة نظريًا ولكنها معقدة عمليًا. تفشل الشبكات، وتتعطل الخوادم، ويحتوي العملاء على أخطاء. تتطلب Webhooks في بيئات الإنتاج منطق إعادة المحاولة، والمعاودة الآمنة، والأمان، والمراقبة.

تطبق PetstoreAPI الحديثة Webhooks جاهزة للإنتاج لتحديثات الطلبات، وعمليات تبني الحيوانات الأليفة، وإشعارات الدفع. يتضمن كل Webhook منطق إعادة المحاولة، والتحقق من التوقيع، والمعاودة الآمنة.

💡
إذا كنت تقوم ببناء أو اختبار Webhooks، فإن Apidog يساعدك على اختبار تسليم الـ Webhook، والتحقق من التوقيعات، ومحاكاة سيناريوهات الفشل. يمكنك اختبار منطق إعادة المحاولة والتحقق من التعامل مع المعاودة الآمنة.
زر

في هذا الدليل، ستتعلم كيفية تصميم Webhooks موثوقة باستخدام أنماط PetstoreAPI الحديثة.

أساسيات Webhook

Webhooks هي طلبات HTTP POST تُرسل إلى عناوين URL المقدمة من العميل عند وقوع الأحداث.

كيف تعمل Webhooks

1. يقوم العميل بتسجيل عنوان URL الخاص بالـ Webhook:

POST /webhooks
{
  "url": "https://client.com/webhooks/petstore",
  "events": ["pet.adopted", "order.completed"]
}

2. يقع الحدث (تبني حيوان أليف)

3. يرسل الخادم الـ Webhook:

POST https://client.com/webhooks/petstore
Content-Type: application/json
X-Webhook-Signature: sha256=abc123...

{
  "event": "pet.adopted",
  "data": {
    "petId": "019b4132",
    "userId": "user-456",
    "timestamp": "2026-03-13T10:30:00Z"
  }
}

4. يستجيب العميل:

200 OK

مشكلة الموثوقية

يمكن أن تفشل Webhooks لأسباب عديدة:

بدون منطق إعادة المحاولة، تُفقد الأحداث. بدون المعاودة الآمنة، تتسبب الـ webhooks المكررة في إجراءات مكررة.

منطق إعادة المحاولة مع التراجع الأُسي

أعد محاولة الـ webhooks الفاشلة مع تأخيرات متزايدة.

استراتيجية التراجع الأُسي

المحاولة 1: فورية
المحاولة 2: بعد ثانية واحدة
المحاولة 3: بعد ثانيتين
المحاولة 4: بعد 4 ثوانٍ
المحاولة 5: بعد 8 ثوانٍ
المحاولة 6: بعد 16 ثانية

لماذا أُسي؟ إذا كان العميل معطلًا، فإن إغراقه بمحاولات إعادة المحاولة لن يساعد. يمنح التراجع الأُسي وقتًا للتعافي.

التطبيق

async function sendWebhook(url, payload, attempt = 1, maxAttempts = 6) {
  try {
    const response = await fetch(url, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'X-Webhook-Signature': generateSignature(payload)
      },
      body: JSON.stringify(payload),
      timeout: 5000 // 5 second timeout
    });

    if (response.ok) {
      return { success: true, attempt };
    }

    // Retry on 5xx errors
    if (response.status >= 500 && attempt < maxAttempts) {
      const delay = Math.pow(2, attempt - 1) * 1000;
      await sleep(delay);
      return sendWebhook(url, payload, attempt + 1, maxAttempts);
    }

    // Don't retry 4xx errors (client error)
    return { success: false, status: response.status };

  } catch (error) {
    // Network error or timeout - retry
    if (attempt < maxAttempts) {
      const delay = Math.pow(2, attempt - 1) * 1000;
      await sleep(delay);
      return sendWebhook(url, payload, attempt + 1, maxAttempts);
    }
    return { success: false, error: error.message };
  }
}

متى تتم إعادة المحاولة

أعد المحاولة عند:

لا تعد المحاولة عند:

قائمة الرسائل المعطلة

بعد الوصول للحد الأقصى من محاولات إعادة المحاولة، انقل الـ webhooks الفاشلة إلى قائمة الرسائل المعطلة للمراجعة اليدوية:

if (!result.success) {
  await deadLetterQueue.add({
    url,
    payload,
    attempts: maxAttempts,
    lastError: result.error,
    timestamp: new Date()
  });
}

المعاودة الآمنة لمنع التكرار

قد يتلقى العملاء نفس الـ Webhook عدة مرات. تمنع المعاودة الآمنة المعالجة المكررة.

مفاتيح المعاودة الآمنة

أدرج معرّفًا فريدًا مع كل Webhook:

{
  "id": "webhook_019b4132",
  "event": "pet.adopted",
  "data": {...}
}

يخزن العميل المعرفات التي تمت معالجتها:

app.post('/webhooks/petstore', async (req, res) => {
  const webhookId = req.body.id;

  // Check if already processed
  const processed = await db.webhooks.findOne({ id: webhookId });
  if (processed) {
    return res.status(200).json({ message: 'Already processed' });
  }

  // Process webhook
  await processPetAdoption(req.body.data);

  // Mark as processed
  await db.webhooks.insert({ id: webhookId, processedAt: new Date() });

  res.status(200).json({ message: 'Processed' });
});

عمليات المعاودة الآمنة

صمم العمليات لتكون معاودة آمنة:

سيء (غير معاود آمن):

// Charging twice causes double charge
await chargeCustomer(userId, amount);

جيد (معاود آمن):

// Charging with idempotency key prevents double charge
await chargeCustomer(userId, amount, { idempotencyKey: webhookId });

التحقق من التوقيع للأمان

تحقق من أن الـ webhooks تأتي من واجهة برمجة التطبيقات الخاصة بك، وليس من مهاجم.

توقيع HMAC

قم بإنشاء توقيع باستخدام مفتاح سري مشترك:

// Server generates signature
const crypto = require('crypto');

function generateSignature(payload, secret) {
  const hmac = crypto.createHmac('sha256', secret);
  hmac.update(JSON.stringify(payload));
  return hmac.digest('hex');
}

// Include in header
headers['X-Webhook-Signature'] = `sha256=${generateSignature(payload, webhookSecret)}`;

العميل يتحقق من التوقيع:

function verifySignature(payload, signature, secret) {
  const expected = generateSignature(payload, secret);
  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(`sha256=${expected}`)
  );
}

app.post('/webhooks/petstore', (req, res) => {
  const signature = req.headers['x-webhook-signature'];

  if (!verifySignature(req.body, signature, WEBHOOK_SECRET)) {
    return res.status(401).json({ error: 'Invalid signature' });
  }

  // Process webhook
  ...
});

التحقق من الطابع الزمني

أدرج طابعًا زمنيًا لمنع هجمات إعادة التشغيل (Replay attacks):

{
  "id": "webhook_019b4132",
  "timestamp": "2026-03-13T10:30:00Z",
  "event": "pet.adopted",
  "data": {...}
}

ارفض الـ webhooks القديمة:

const webhookAge = Date.now() - new Date(req.body.timestamp);
if (webhookAge > 5 * 60 * 1000) { // 5 minutes
  return res.status(400).json({ error: 'Webhook too old' });
}

معالجة المهلات

قم بتعيين مهلات صارمة لمنع العملاء البطيئين من حظر نظامك.

مهلة 5 ثوانٍ

const response = await fetch(url, {
  method: 'POST',
  body: JSON.stringify(payload),
  timeout: 5000 // 5 seconds
});

لماذا 5 ثوانٍ؟ يجب أن تعود الـ webhooks فورًا. إذا استغرق العميل وقتًا أطول، فإنه يقوم بمعالجة متزامنة (نمط خاطئ).

نمط المعالجة غير المتزامنة

سيء (متزامن):

app.post('/webhooks/petstore', async (req, res) => {
  // This takes 30 seconds - webhook will timeout
  await processOrder(req.body.data);
  await sendEmail(req.body.data);
  await updateInventory(req.body.data);

  res.status(200).json({ message: 'Processed' });
});

جيد (غير متزامن):

app.post('/webhooks/petstore', async (req, res) => {
  // Return immediately
  res.status(200).json({ message: 'Received' });

  // Process asynchronously
  queue.add('process-webhook', req.body);
});

كيف تطبق PetstoreAPI الحديثة Webhooks

تطبق PetstoreAPI الحديثة Webhooks جاهزة للإنتاج.

أحداث Webhook

pet.adopted - تم تبني الحيوان الأليف
pet.status_changed - تغيرت حالة الحيوان الأليف
order.created - تم إنشاء الطلب
order.completed - اكتمل الطلب
payment.succeeded - نجح الدفع
payment.failed - فشل الدفع

حمولة Webhook

{
  "id": "webhook_019b4132-70aa-764f-b315-e2803d882a24",
  "event": "pet.adopted",
  "timestamp": "2026-03-13T10:30:00Z",
  "data": {
    "petId": "019b4132-70aa-764f-b315-e2803d882a24",
    "userId": "user-456",
    "orderId": "order-789",
    "adoptionDate": "2026-03-13"
  },
  "apiVersion": "v1"
}

تكوين إعادة المحاولة

الأمان

اختبار Webhooks باستخدام Apidog

يدعم Apidog اختبار الـ webhooks.

اختبار تسليم الـ Webhook

  1. أنشئ نقطة نهاية Webhook وهمية في Apidog
  2. سجل نقطة النهاية مع PetstoreAPI
  3. قم بتشغيل الحدث (تبني حيوان أليف)
  4. تحقق من استلام الـ Webhook
  5. تحقق من تنسيق الحمولة

اختبار التحقق من التوقيع

// Apidog test script
const signature = pm.request.headers.get('X-Webhook-Signature');
const payload = pm.request.body.raw;
const secret = pm.environment.get('WEBHOOK_SECRET');

const expected = generateSignature(payload, secret);
pm.test('Signature valid', () => {
  pm.expect(signature).to.equal(`sha256=${expected}`);
});

اختبار منطق إعادة المحاولة

  1. أعد خطأ 500 من نقطة النهاية الوهمية
  2. تحقق من محاولات إعادة المحاولة باستخدام التراجع الأُسي
  3. تحقق من قائمة الرسائل المعطلة بعد الوصول للحد الأقصى من المحاولات

اختبار المعاودة الآمنة

  1. استلم الـ Webhook
  2. أعد استجابة 200
  3. استلم نفس الـ Webhook مرة أخرى (إعادة محاولة محاكية)
  4. تحقق من عدم وجود معالجة مكررة

الخلاصة

تتطلب Webhooks الموثوقة ما يلي:

تطبق PetstoreAPI الحديثة جميع هذه الأنماط. راجع وثائق الـ Webhook للحصول على أمثلة كاملة.

اختبر الـ webhooks الخاصة بك باستخدام Apidog للتحقق من منطق إعادة المحاولة والتوقيعات والمعاودة الآمنة قبل الانتقال إلى بيئة الإنتاج.

زر

الأسئلة الشائعة

كم عدد محاولات إعادة المحاولة التي يجب أن تحتوي عليها الـ webhooks؟

5-10 محاولات مع التراجع الأُسي. يغطي هذا الانقطاعات المؤقتة (5-17 دقيقة) دون إثقال كاهل العميل.

هل يجب أن تعيد الـ webhooks المحاولة عند أخطاء 4xx؟

لا. تشير أخطاء 4xx إلى مشاكل العميل (عنوان URL خاطئ، فشل المصادقة). لن تؤدي إعادة المحاولة إلى إصلاح هذه المشاكل. أعد المحاولة فقط عند أخطاء 5xx وأخطاء الشبكة.

كم يجب أن تكون مدة مهلات الـ Webhook؟

الحد الأقصى 5 ثوانٍ. يجب أن يعيد العملاء استجابة 200 فورًا ويعالجوا بشكل غير متزامن. تشير المهلات الأطول إلى أن العميل يقوم بمعالجة متزامنة.

ماذا لو لم يستجب العميل أبدًا للـ webhooks؟

بعد الوصول للحد الأقصى من محاولات إعادة المحاولة، انقلها إلى قائمة الرسائل المعطلة. نبه العميل عبر البريد الإلكتروني. فكر في تعطيل الـ webhooks لهذا العميل بعد الإخفاقات المتكررة.

هل يجب أن تكون عناوين URL الخاصة بالـ Webhook عبر HTTPS؟

نعم، يجب دائمًا طلب HTTPS. يمكن اعتراض وتعديل الـ webhooks عبر HTTP. ترفض PetstoreAPI الحديثة عناوين URL الخاصة بالـ Webhook التي تستخدم HTTP.

كيف تمنع هجمات إعادة التشغيل؟

أدرج طابعًا زمنيًا في الحمولة وارفض الـ webhooks التي يزيد عمرها عن 5 دقائق. ادمج هذا مع التحقق من التوقيع.

هل يمكن للعملاء طلب إعادة تسليم الـ Webhook؟

نعم. توفر PetstoreAPI الحديثة نقطة نهاية لإعادة تسليم webhooks محددة: POST /webhooks/{id}/redeliver

كيف تختبر الـ webhooks محليًا؟

استخدم أدوات مثل ngrok لتعريض الخادم المحلي (localhost) للإنترنت، أو استخدم خادم Apidog الوهمي لمحاكاة نقاط نهاية الـ Webhook أثناء التطوير.

ممارسة تصميم API في Apidog

اكتشف طريقة أسهل لبناء واستخدام واجهات برمجة التطبيقات