الدليل

الأخطاء

غلاف واحد لكل إخفاق، وعشرة رموز عامة تبني عليها قرارك، ورسالة مترجَمة منفصلة يجب ألا يحلّلها برنامجك ولا يقارنها أبدًا.

كل رد غير ناجح من واجهة X-Radius هو الكائن نفسه. لا شكل خطأ ثانٍ، ولا جسم نصّي عارٍ، ولا صفحة HTML — حتى في حالة الـ 500.

الغلاف

{
  "error": {
    "code": "ERR_VALIDATION",
    "message": "Request validation failed.",
    "request_id": "8f2c1d0a4b",
    "details": { "reason": "invalid_expiration" }
  }
}
  • code صنف، لا حادثة بعينها. وهو ثابت وبأحرف كبيرة وآمن أن تبني عليه قرارك.
  • message نثر للبشر، مترجَم سلفًا إلى لغة المنادي. وليس عقدًا. عامله على أنه غير مستقر في صياغته ولا في لغته.
  • request_id يحدّد الطلب بعينه في سجل الخادم. اذكره في محادثة الدعم؛ فهو عادةً الفرق بين تشخيص وتخمين.
  • details موجود في بعض الإخفاقات فقط. وحين يوجد يحمل reason، وهو مميِّز ثابت يقرؤه البرنامج، ويحمل أحيانًا حقلًا أرسله المنادي معادًا كما هو، ليبلّغ البرنامج عما حاول فعله بلا تحليل نثر.

وردود النجاح هي الصورة المقابلة: كائن واحد تحت data، مع كتلة meta تضيفها نقاط القوائم.

الرموز العامة العشرة

هذه العشرة هي كامل مفردات حقل الصنف. وكل حالة أدناه هي الحالة المتعارف عليها؛ والمعالج يختار الحالة صراحةً، فقد يظهر الرمز مع حالة أخرى حيث يقتضي السياق.

الرمز الحالة المعنى
ERR_VALIDATION 400 الطلب مشوَّه، أو قيمة خارج المدى أو غير مسموحة. وهو الأكثر شيوعًا بفارق كبير.
ERR_UNAUTHORIZED 401 بيانات الاعتماد مفقودة أو مشوَّهة أو لم تعد سارية.
ERR_FORBIDDEN 403 بيانات الاعتماد سليمة؛ الصلاحية ليست كذلك.
ERR_NOT_FOUND 404 لا سجل بهذا المعرّف — أو سجل لا يحقّ لك رؤيته. والجوابان متطابقان عن قصد.
ERR_CONFLICT 409 الطلب يناقض الحالة الراهنة: اسم مستخدم مأخوذ، أو كرت استُهلك، أو مفتاح منع تكرار مرتبط بموضوع آخر.
ERR_RATE_LIMITED 429 نفدت ميزانية طلبات. انظر حدود المعدل.
ERR_INTERNAL 500 عطل من جهتنا. وrequest_id هو الشيء الوحيد المفيد الذي ترسله إلينا.
ERR_TIMEOUT 503 لم يتسع العمل لميزانية الطلب أو ميزانية الجملة. لا شيء معطوب؛ أعد المحاولة، ويفضَّل بنطاق أضيق.
ERR_LICENSE_BLOCKED 403 المستأجر تجاوز سقف مشتركيه أو انتهى ترخيصه. وواجهة الإدارة كلها مقفلة على صفحة الترخيص حتى يُحلّ ذلك.
ERR_MAINTENANCE 503 وُضعت النسخة في وضع الصيانة من لوحة المشغّل. وليس حكمًا على طلبك.

واثنان من هذه يستحقان نظرةً ثانية:

ERR_TIMEOUT هو 503 ويختلف عن ERR_INTERNAL عن قصد. يُطلق حين تنقضي ميزانية الطلب أو مهلة جملة قاعدة البيانات. لا شيء خاطئ؛ الاستعلام ببساطة أكبر من الوقت المسموح. فضيّق المرشّح أو الصفحة وأعد المحاولة.

وERR_NOT_FOUND يغطي "غير موجود" و"موجود لكنه خارج شجرة مديرك" معًا. فالـ 403 في تلك المسارات يؤكد وجود السجل ويجعل المعرّفات قابلة للتعداد، فالجوابان متطابقان حرفًا بحرف، بما في ذلك details.reason.

ويوجد رمز آخر قد يصلك على واجهة المستأجر وليس في ذلك الجدول: ERR_UNAVAILABLE بحالة 503، مع details.reason تساوي site_offline، حين يطفئ مشغّل بوابة المستأجر. ويُجاب به عند الدخول وعند مداخل بوابة المشترك فقط.

الرموز مقابل الأسباب

حقل code خشن بحكم التصميم، وعدة نتائج شديدة الاختلاف تتشارك رمزًا واحدًا. فستة إخفاقات دخول مختلفة كلها تجيب ERR_UNAUTHORIZED: لا حساب بهذا الاسم، كلمة مرور خاطئة، مطلوب تحقق بخطوتين، تحقق بخطوتين خاطئ، جلسة أُبطلت، رمز انتهى. والصنف واحد فعلًا، والبرنامج الذي يريد التفريق بينها يحتاج شيئًا أدقّ.

وذلك الشيء هو details.reason. وهو دائمًا مفتاح الرسالة الذي بنى به الخادم النثر المترجَم، فيبقى الاثنان متوافقين بالبناء. والمفاتيح نحو ألف ومئتين، فلا تحاول حصرها — بدّل على الحفنة التي يحتاجها تكاملك فعلًا، ودع الباقي يسقط إلى الرمز.

{
  "error": {
    "code": "ERR_UNAUTHORIZED",
    "message": "Two-factor authentication is required.",
    "request_id": "1c7f0b99e2",
    "details": { "reason": "mfa_required" }
  }
}

وليس كل إخفاق يحمل details. فإخفاقات المصادقة وحدود المعدل ورفض مفاتيح منع التكرار تحملها. أما رفض الصلاحية البسيط فلا: الـ 403 بالرمز ERR_FORBIDDEN الصادر عن بوابة الصلاحيات يحمل الرمز والرسالة فقط.

الرسائل مترجَمة، فلا تطابقها أبدًا

يُعرض حقل message بلغة المنادي، تُختار من ترويسة Accept-Language وترتدّ إلى لغة المستأجر الافتراضية. فالإخفاق نفسه نثرٌ إنجليزي عند عميل ونثرٌ عربي عند آخر:

curl -s https://acme.example.com/api/v1/users/999999 \
  -H "Authorization: Bearer $XRADIUS_TOKEN" \
  -H "Accept-Language: ar"

والبرنامج الذي يقارن نص الرسالة يُكسر لحظة يحسّن مترجم جملةً، ويُكسر عند كل منادٍ لغته ليست اللغة التي كُتب البرنامج عليها. ابنِ قرارك على error.code، ثم على error.details.reason إن احتجت التفصيل. واعرض message للناس، وسجّل request_id، وعامل الاثنين بوصفهما بياناتٍ تمرّرها لا منطقًا تعتمد عليه.

معالجة عملية

البرنامج المعقول يفرّق بين أربع حالات ويتجاهل ما عداها:

  • أعد المحاولة كما هيERR_TIMEOUT وERR_MAINTENANCE، وERR_INTERNAL بعد مهلة. تراجع تدريجيًا، ولا تطرق الباب بعنف.
  • أعد المحاولة بعد انتظارERR_RATE_LIMITED. لا ترويسة Retry-After، فتراجع وفق جدولك أنت.
  • أصلح الطلبERR_VALIDATION وERR_CONFLICT. فإعادة إرسال البايتات نفسها ستفشل بالطريقة نفسها.
  • أصلح بيانات الاعتماد أو الإعدادERR_UNAUTHORIZED وERR_FORBIDDEN وERR_LICENSE_BLOCKED. لا شيء يفعله برنامجك وقت التشغيل يحلّ هذه.

وERR_NOT_FOUND هو الخامس، وينتمي إلى أيٍّ من هذه الأربع يقرّره نموذج بياناتك.

وإعادة محاولة أي عملية تحرّك مالًا أو تجهّز خدمة يجب أن تعيد استعمال مفتاح منع التكرار الأصلي. انظر منع التكرار؛ فالخطأ هنا هو ما يحوّل انقضاء مهلة إلى خصم مزدوج.

آخر تحديث

اطرح سؤالًا

جرّبه على شبكتك.

50 مشترك لمدة 7 أيام، من غير ما تدفع حاجة.