في هذه الصفحة
- نظرة سريعة
- ردود البوابة
- بوابات بصيغة الرد الأحدث
- api_key_missing
- api_key_invalid
- access_denied
- subscription_required
- subscription_inactive
- subscription_not_started
- subscription_expired
- quota_exceeded
- rate_limit_exceeded
- route_not_found
- service_unavailable
- upstream_error
- إعادة المحاولة مع انتظار متزايد وعشوائية في المدة
- حين تحتاج إلى الدعم
- انظر أيضاً
نظرة سريعة#
تردّ البوابة حين ترفض طلباً بجسم JSON فيه حقل message. ويحمل كل رد، ردّ البوابة وردّ المزوّد، ترويسة X-Kong-Request-Id. وأي خطأ تصدره خدمة المزوّد نفسها يمرّ دون تغيير، بحالة المزوّد وجسمه.
{
"message": "No active subscription for this product"
}الاستدعاء الذي لا تستطيع البوابة مطابقته مع اشتراك يحصل على 403 لا 401، ما لم يكن المضيف يعمل بالصيغة الأحدث الموصوفة أدناه. ويشمل ذلك استدعاءً بلا مفتاح، وبمفتاح مجهول، وبمفتاح البيئة الأخرى، وبمفتاح في ترويسة باسم آخر. لا تفرّق البوابة بين هذه الحالات، فالرسالة واحدة.
ردود البوابة#
| الحالة | message | معناها وما تفعله |
|---|---|---|
403 | No active subscription for this product | لم تستطع البوابة مطابقة مفتاحك مع اشتراك نشط في هذا المنتج. تحقق من المضيف واسم الترويسة والمفتاح وبيئته، ثم من إضافة المنتج إلى التطبيق. انظر الجدول التالي. |
403 | Subscription is not active | تعرف البوابة الاشتراك لكنه غير نشط، كأن يكون قد انتهى، أو يكون تجديده بانتظار الدفع أو الموافقة. افتح اشتراكاتي. |
403 | Subscription quota exceeded | نفدت حصة اشتراكك. لا تكرّر المحاولة. |
429 | Endpoint quota exceeded | نفدت حصة نقطة النهاية هذه. لا تكرّر المحاولة. |
403 | No endpoint quota rule found for this consumer | المنتج مسعَّر لكل نقطة نهاية وليست لاشتراكك حصة لهذه النقطة. تحقق من نقاط نهاية اشتراكك. |
403 | Authentication required، Consumer not identified | لم تستطع البوابة تحديد التطبيق. أرسل المفتاح في ترويسة api360key. |
404 | no Route matched with those values | لا يوجد توجيه (route) يطابق الطلب. تحقق من عنوان البوابة ومعرّف المنتج و/v والإصدار والمسار والطريقة. ويحمل الجسم أيضاً request_id. |
503 | Subscription service unavailable، Endpoint quota service unavailable | جزء من البوابة غير متاح مؤقتاً. أعد المحاولة مع زيادة مدة الانتظار تدريجياً. |
500 | Route configuration error | المسار مهيّأ خطأً من جهة المنصة. تواصل مع الدعم واذكر معرّف الطلب. |
400 | Endpoint quota rule misconfigured | قاعدة حصة نقطة النهاية خاطئة من جهة المنصة. تواصل مع الدعم واذكر معرّف الطلب. |
حين تقرأ 403 مع No active subscription for this product فابحث عن خطئك في هذا الجدول:
| ما فعلته | ما تغيّره |
|---|---|
لم ترسل مفتاحاً، أو وضعته في ترويسة أخرى مثل Authorization أو x-api-key | أرسل api360key: <key>. ويُقبل المفتاح أيضاً معاملَ استعلام باسم api360key، لكن عنوان URL يُكتب في السجلات، ففضّل الترويسة. |
| استخدمت مفتاح تطبيق «اختبار» على بوابة الإنتاج، أو العكس | استخدم مفتاح تطبيق من بيئة البوابة (Sandbox وبيئة الإنتاج). |
| حذفت المفتاح | استخدم مفتاحاً ما زال موجوداً في التطبيق (التطبيقات والمفاتيح). |
| لم تضف المنتج إلى التطبيق، أو لم تشترك | اشترك ثم أضف المنتج إلى التطبيق (الاشتراكات). |
| استدعيت بعد ثوانٍ من إجراء التغيير | انتظر دقيقة وأرسل الطلب من جديد. |
# a key the gateway does not know: the same answer as no key at all curl -sS "$API360_BASE_URL$API360_PATH" -H "api360key: not-a-real-key"
# a key sent in another header is not read curl -sS -o /dev/null -w "%{http_code}\n" "$API360_BASE_URL$API360_PATH" -H "x-api-key: not-a-real-key"
# no product behind this path curl -sS "$API360_GATE_URL/no-such-product/v1/x"
بوابات بصيغة الرد الأحدث#
تردّ بعض عناوين البوابة بصيغة أحدث. الرد بهذه الصيغة فيه كائن JSON اسمه error ويحتفظ برموز الحالة نفسها. اعتمد على code في معالجة الخطأ: أما message فبالعربية أو الإنجليزية بحسب ترويسة Accept-Language في طلبك.
{
"error": {
"code": "api_key_missing",
"message": "No API key was provided. Send your key in the api360key header.",
"request_id": "03284e42d54f8e25b7cce16b65f7a86a",
"docs_url": "https://api360.sa/docs/consumer/errors-and-retries#api_key_missing"
}
}في مضيف كهذا يكون الاستدعاء بلا مفتاح 401، وللمفتاح المفقود أو غير الصالح رمزه الخاص. والرموز التي تقابلها غالباً فيما يلي. وdocs_url في الرد يشير إلى رمزه أدناه.
api_key_missing#
401. لم يحمل الطلب مفتاحاً. أرسله في ترويسة api360key.
api_key_invalid#
401. لا تعرف البوابة المفتاح أو بيانات الاعتماد، فهي خاطئة أو محذوفة أو من البيئة الأخرى. تحقق من المفتاح مقابل التطبيق والمضيف.
access_denied#
403. المفتاح صالح لكن التطبيق غير مسموح له بهذا المنتج. أضف المنتج إلى التطبيق.
subscription_required#
403. المفتاح صالح ولا يوجد اشتراك نشط في هذا المنتج. اشترك فيه.
subscription_inactive#
403. تعرف البوابة الاشتراك لكنه غير نشط، كأن يكون قد انتهى، أو يكون تجديده بانتظار الدفع أو الموافقة.
subscription_not_started#
403. يبدأ الاشتراك لاحقاً. أعد المحاولة بعد تاريخ بدئه.
subscription_expired#
403. انتهى الاشتراك. جدّده.
quota_exceeded#
429. نفدت حصتك. لا تكرّر المحاولة إلا بعد المدة المذكورة في Retry-After، أو غيّر اشتراكك.
rate_limit_exceeded#
429. طلبات كثيرة جداً. أعد المحاولة بعد المدة المذكورة في Retry-After.
route_not_found#
404. لا يوجد منتج يطابق المضيف والمسار والطريقة.
service_unavailable#
503. الخدمة غير متاحة مؤقتاً. أعد المحاولة مع زيادة مدة الانتظار تدريجياً، بعد المدة المذكورة في Retry-After.
upstream_error#
502. ردّت خدمة المزوّد بجواب غير صالح أو تعذّر الوصول إليها. أعد المحاولة مع زيادة مدة الانتظار تدريجياً.
توجد رموز أخرى للأغراض نفسها، وتقول message فيها ما تفعله. وإذا جاء 500 ومعه معرّف الطلب في الجسم فتواصل مع الدعم.
إعادة المحاولة مع انتظار متزايد وعشوائية في المدة#
أعد المحاولة في الإخفاقات المؤقتة فقط: خطأ الشبكة، والردود 502 و503 و504. أعدها ثلاث مرات على الأكثر، وانتظر مدة عشوائية تطول في كل مرة، حتى لا يعيد كل عملائك المحاولة في اللحظة نفسها. ولا تُعِد أبداً إرسال طلب رُفض بسبب حصة أو اشتراك (403 و429 كما سبق)، ولا 404، ولا أي 4xx آخر: الانتظار لا يغيّر الجواب.
const RETRY = new Set([502, 503, 504]); const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); // call(fn): fn sends the request and returns a Response; the result is the first answer that is not worth a retry async function call(fn, { tries = 3, baseMs = 1000 } = {}) { for (let i = 0; ; i++) { let res; try { res = await fn(); } catch (err) { if (i >= tries - 1) throw err; // a network error: try again, then give up await sleep(2 ** i * baseMs + Math.random() * 0.4 * baseMs); continue; } if (!RETRY.has(res.status) || i >= tries - 1) return res; await sleep(2 ** i * baseMs + Math.random() * 0.4 * baseMs); } } // demo with a fake service that answers 503 twice and then 200 let sent = 0; const res = await call(async () => new Response("{}", { status: ++sent < 3 ? 503 : 200 }), { baseMs: 1 }); console.log(res.status === 200 ? `ok:${sent}` : `failed:${res.status}`);
الطلب الذي يغيّر بيانات ليس آمناً أن يُعاد بعد انقضاء المهلة: فقد تكون المحاولة الأولى نجحت، وتنفّذ الثانية العمل مرتين. لا تعد مثل هذا الطلب إلا إذا قال المنتج إن ذلك آمن.
حين تحتاج إلى الدعم#
أرسل قيمة X-Kong-Request-Id للرد، ووقت الاستدعاء، والمنتج، والبيئة (احصل على المساعدة). وفي بوابة بالصيغة الأحدث أرسل أيضاً request_id من الجسم.
الصيغة الأحدث للرد في كل عناوين البوابة، وRetry-After في ردود تحديد المعدل، وترويسة Idempotency-Key التي تجعل إعادة طلب POST آمنة.