عند استدعاء واجهة API، تُعدّ 401 Unauthorized و403 Forbidden و429 Too Many Requests أكثر ثلاثة أنواع من الأخطاء شيوعًا.
كلها تنتمي إلى أخطاء العميل 4xx، لكن طرق حلها مختلفة تمامًا:
- 401: فشل المصادقة——لا يستطيع الخادم تأكيد "من أنت"
- 403: تم رفض الوصول——يفهم الخادم الطلب، لكنه لا يسمح بتنفيذه
- 429: طلبات كثيرة جدًا——تتجاوز سرعة الاستدعاء أو الاستخدام الحد المسموح
إذا أُعيدت المحاولة مباشرةً دون التمييز بين أنواع الأخطاء، فلن يحل ذلك المشكلة فحسب، بل قد يتسبب أيضًا في عاصفة إعادة محاولات، وقد يؤدي حتى إلى فرض قيود إضافية على الواجهة.
ستوضح هذه المقالة، من خلال قائمة استكشاف الأخطاء وطلبات curl وكود Node.js، كيفية التعامل عند مواجهة هذه الأنواع الثلاثة من الأخطاء.
¶ فهم 401 و403 و429 من خلال جدول واحد
| رمز الحالة | المعنى الأساسي | الأسباب الشائعة | هل ينبغي إعادة المحاولة فورًا |
|---|---|---|---|
401 Unauthorized |
غياب بيانات اعتماد مصادقة صالحة | خطأ في API Key، انتهاء Token، خطأ في تنسيق ترويسة المصادقة | لا ينبغي إعادة المحاولة بنفس الشكل |
403 Forbidden |
الخادم يرفض معالجة الطلب | صلاحيات غير كافية، قيود IP أو المنطقة، سياسة الموارد، حظر WAF | عادةً لا ينبغي |
429 Too Many Requests |
الطلبات تتجاوز حد المعدل أو الحصة | تزامن مرتفع جدًا، تجاوز QPS، استنفاد الرصيد | أعد المحاولة بعد الانتظار |
تجدر الإشارة إلى أنه على الرغم من أن الاسم الإنجليزي لـ 401 هو Unauthorized، فمن الأنسب في استكشاف الأخطاء الفعلي فهمه على أنه "لم يجتز المصادقة"؛ أما 403 فعادةً ما يرتبط بالتفويض أو سياسة الوصول.
¶ أولًا، 401 Unauthorized: افحص بيانات اعتماد المصادقة أولًا

يشير HTTP 401 Unauthorized إلى أن الطلب يفتقر إلى بيانات اعتماد مصادقة صالحة مطلوبة للوصول إلى المورد المستهدف. عادةً ما يخبر رد 401 القياسي العميل، عبر ترويسة الاستجابة WWW-Authenticate، بنظام المصادقة الذي يتوقع الخادم استخدامه.
¶ الأسباب الشائعة
- لم يتم إرسال ترويسة الطلب
Authorization - تمت كتابة API Key أو Access Token بشكل خاطئ
- انتهت صلاحية Token أو تم إلغاؤه
- نظام المصادقة خاطئ، مثل نسيان
Bearer - لم يتم تحميل متغيرات البيئة بشكل صحيح
- تم استخدام مفتاح لبيئة خاطئة
- فُقدت ترويسة المصادقة عند تمرير الطلب عبر وكيل أو بوابة
- فرق الوقت بين العميل والخادم كبير جدًا، مما يؤدي إلى فشل التوقيع
¶ أخطاء شائعة
تتطلب الواجهة Bearer Token:
Authorization: Bearer YOUR_ACCESS_TOKEN
لكن العميل أرسلها بهذا الشكل:
Authorization: YOUR_ACCESS_TOKEN
أو كتبها بشكل خاطئ هكذا:
Authentication: Bearer YOUR_ACCESS_TOKEN
قد تؤدي كلتا الحالتين إلى إرجاع 401.
¶ الاستكشاف باستخدام curl
لا تكتفِ بعرض جسم الاستجابة في البداية. أضف -i، وافحص رمز الحالة وترويسات الاستجابة معًا:
curl -i "https://api.example.com/v1/profile" \
-H "Authorization: Bearer $API_TOKEN" \
-H "Accept: application/json"
ركّز على فحص:
- ما إذا تم إرسال
Authorizationبالفعل - ما إذا كان نظام المصادقة صحيحًا
- ما إذا كانت هناك مسافات أو أسطر جديدة قبل Token أو بعده
- ما الذي أرجعه
WWW-Authenticate - ما إذا كانت هناك معلومات خطأ مثل
invalid_tokenوexpired_tokenفي جسم الاستجابة
إذا كنت بحاجة إلى عرض عملية الطلب بمزيد من التفصيل، يمكنك استخدام:
curl -v "https://api.example.com/v1/profile" \
-H "Authorization: Bearer $API_TOKEN"
ملاحظة: قد تتضمن سجلات التصحيح Token. لا ترسل السجل الكامل مباشرةً إلى Issue عام أو دردشة جماعية أو تذكرة دعم.
¶ هل ينبغي إعادة محاولة 401؟
لا تستخدم بيانات الاعتماد غير الصالحة نفسها لإعادة المحاولة مرارًا.
التدفق الموصى به:
- تحقّق مما إذا كان الطلب يحمل معلومات المصادقة
- تحقّق مما إذا كانت Token منتهية الصلاحية أو ملغاة أو منسوخة بشكل خاطئ
- إذا كان Refresh Token مدعومًا، فحدّث رمز الوصول مرة واحدة
- أعد المحاولة مرة واحدة باستخدام Token جديدة
- إذا استمر إرجاع 401، فأوقف إعادة المحاولة وسجّل الخطأ
إذا كنت تستخدم API Key ثابتًا، فينبغي التحقق من حالة المفتاح أو استبداله بمفتاح صالح، بدلًا من إعادة المحاولة بشكل متكرر.
¶ ثانيًا، 403 Forbidden: قد تنجح المصادقة، لكن الطلب ما يزال مرفوضًا

يشير 403 Forbidden إلى أن الخادم قد فهم الطلب بالفعل، لكنه يرفض معالجته. بالنسبة إلى أخطاء الصلاحيات النموذجية، حتى إعادة المصادقة لن تحل المشكلة تلقائيًا؛ وإذا لم يتم تعديل الطلب أو إعدادات الصلاحيات، فعادةً ما ستفشل الطلبات المتكررة أيضًا.
¶ الأسباب الشائعة
- الحساب أو المفتاح الحالي يفتقر إلى الصلاحيات المطلوبة
- Scope الخاصة بـ Token غير كافية
- تم الوصول إلى مورد لا ينتمي إلى المشروع أو المستأجر الحالي
- عنوان IP المصدر ليس ضمن القائمة البيضاء
- منطقة مصدر الطلب خاضعة لقيود
- تم الحظر بواسطة WAF أو جدار الحماية أو نظام مكافحة إساءة الاستخدام
- تم تعطيل الحساب أو المشروع أو المورد
- الواجهة متاحة فقط لباقات أو أدوار محددة
- التوقيع صالح، لكن نطاق المورد في التوقيع غير متطابق
- في سيناريو المتصفح، توجد قيود بسبب سياسة CSRF أو Origin أو Referer
¶ الفرق بين 401 و403
يمكن الحكم بسرعة باستخدام جملتين:
- 401: لا يستطيع الخادم تأكيد من أنت
- 403: يعرف الخادم أو يفهم هويتك وطلبك، لكنه لا يسمح لك بفعل ذلك
على سبيل المثال، يقوم عضو عادي يحمل Token صالحة باستدعاء واجهة "حذف المنظمة":
curl -i -X DELETE \
"https://api.example.com/v1/organizations/org_123" \
-H "Authorization: Bearer $API_TOKEN"
إذا كانت Token صالحة، لكن الحساب ليس مسؤول المنظمة، فقد يعيد الخادم:
HTTP/1.1 403 Forbidden
Content-Type: application/json
{
"error": "insufficient_permissions",
"message": "Administrator role is required."
}
¶ ترتيب استكشاف 403
¶ 1. اقرأ جسم الاستجابة
ابحث أولًا عن رمز الخطأ، أو الدور أو الصلاحية المفقودة، أو Scope المطلوبة، أو معرّف المورد المرفوض، وكذلك التنبيهات المتعلقة بسياسات IP أو المنطقة أو الأمان.
¶ 2. افحص Token Scope
على سبيل المثال، قد تتطلب قراءة البيانات فقط data:read، لكن إنشاء البيانات قد يتطلب data:write. صلاحية Token لا تعني امتلاك جميع الصلاحيات.
¶ 3. افحص ملكية المورد
أكد أن معرّف المشروع ومعرّف المنظمة ومعرّف المستأجر ومعرّف المستخدم والمنطقة أو البيئة تنتمي، مع بيانات الاعتماد الحالية، إلى الحساب نفسه أو نطاق التفويض نفسه.
¶ 4. افحص سياسات الشبكة والأمان
إذا كان الكود يعمل بشكل طبيعي محليًا، لكنه يعيد 403 بعد النشر، فيجب التركيز على فحص عنوان IP الصادر من الخادم، والقائمة البيضاء لعناوين IP، وإعدادات الوكيل، وCDN، وWAF، والمنطقة الجغرافية لمصدر الطلب، وترويسات الطلب ذات الصلة.
¶ لا تستنتج بناءً على رمز الحالة فقط
قد لا تكون تطبيقات API في الواقع متسقة تمامًا. قد تعيد بعض المنصات 403 عند تفعيل تحديد المعدل، بدلًا من 429. على سبيل المثال، قد تعيد GitHub REST API الرمز 403 أو 429 عند تجاوز حد المعدل، وتوضح حالة التقييد عبر ترويسات الاستجابة مثل x-ratelimit-remaining وx-ratelimit-reset أو retry-after.
لذلك، عند مواجهة 403، يجب أيضًا فحص ما يلي بشكل شامل:
- رمز خطأ الأعمال في جسم الاستجابة
Retry-AfterX-RateLimit-RemainingX-RateLimit-Reset- الوثائق الرسمية للمنصة
¶ هل يجب إعادة محاولة 403؟
بالنسبة إلى 403 الناتج عن عدم كفاية الصلاحيات أو قيود IP أو سياسة المورد، فإن إعادة المحاولة كما هي لا معنى لها.
الإجراء الصحيح هو تعديل الصلاحيات أو Token Scope، واستخدام الحساب أو المشروع الصحيح، وضبط القائمة البيضاء وسياسات الأمان، وتصحيح معرّف المورد، والتأكد مما إذا كانت الخدمة أو الباقة تدعم هذه الواجهة. فقط عندما توضح المنصة صراحةً أن هذا الـ 403 يمثل في الواقع تحديدًا مؤقتًا للمعدل، ينبغي الانتظار ثم إعادة المحاولة وفقًا لقواعد تحديد المعدل.
¶ ثالثًا، 429 Too Many Requests: خفّض السرعة أولًا، ثم أعد المحاولة

يشير 429 Too Many Requests إلى أن العميل أرسل عددًا كبيرًا جدًا من الطلبات خلال فترة زمنية، أي تم تفعيل حد المعدل. يمكن للخادم إخبار العميل عبر Retry-After بالمدة التي ينبغي انتظارها قبل إعادة المحاولة.
¶ الأسباب الشائعة
- عدد كبير جدًا من الطلبات خلال وقت قصير
- عدد مهام متزامنة مرتفع جدًا
- عدة خدمات تشترك في نفس API Key
- كود إعادة المحاولة لا يحتوي على آلية انتظار
- تنفيذ المهام المجدولة بشكل مركز في الوقت نفسه
- الطلبات غير مخزنة مؤقتًا، مع جلب البيانات نفسها بشكل متكرر
- استنفاد حصة حساب أو IP أو مشروع واحد
- حدود استخدام الباقة أو الرصيد
¶ افحص ترويسات الاستجابة أولًا
curl -i "https://api.example.com/v1/resources" \
-H "Authorization: Bearer $API_TOKEN"
ركّز على:
Retry-After: 30
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1710000000
قد تختلف أسماء ترويسات الاستجابة بين المنصات، ويجب الرجوع إلى وثائق المنصة.
¶ المعالجة الصحيحة لـ Retry-After
الصيغتان الشائعتان لـ Retry-After هما عدد الثواني أو تاريخ HTTP:
Retry-After: 30
Retry-After: Wed, 21 Oct 2026 07:28:00 GMT
من الأفضل أن يدعم العميل كلتا الصيغتين.
¶ لماذا لا يمكن إعادة المحاولة فورًا؟
إذا تمت إعادة المحاولة فورًا بعد تحديد معدل الطلب، فسيظل الطلب الجديد خاضعًا لتحديد المعدل؛ وقد تعيد عدة عملاء المحاولة في الوقت نفسه، مما يؤدي إلى “اندفاع القطيع”. الطريقة الأكثر أمانًا هي:
- الالتزام بـ
Retry-Afterكأولوية - استخدام التراجع الأسي عند عدم وجود وقت انتظار محدد
- إضافة تذبذب عشوائي إلى وقت الانتظار
- تعيين الحد الأقصى لعدد مرات إعادة المحاولة
- إرجاع خطأ واضح بعد الوصول إلى الحد الأقصى
¶ Node.js: معالجة 429 بأمان
يستخدم المثال التالي fetch المدمج في Node.js، ويحلل Retry-After بأولوية؛ وإذا لم يوفر الخادم ترويسة الاستجابة هذه، فإنه يستخدم تراجعًا أسيًا مع تذبذب عشوائي.
const sleep = (ms) =>
new Promise((resolve) => setTimeout(resolve, ms));
function parseRetryAfter(value) {
if (!value) return null;
const seconds = Number(value);
if (Number.isFinite(seconds) && seconds >= 0) {
return seconds * 1000;
}
const timestamp = Date.parse(value);
if (!Number.isNaN(timestamp)) {
return Math.max(0, timestamp - Date.now());
}
return null;
}
async function fetchWithRetry(url, options = {}, config = {}) {
const {
maxRetries = 3,
baseDelayMs = 1000,
maxDelayMs = 30_000,
} = config;
for (let attempt = 0; attempt <= maxRetries; attempt++) {
const response = await fetch(url, options);
if (response.status !== 429) {
return response;
}
if (attempt === maxRetries) {
throw new Error(
`请求持续受到限流,已达到最大重试次数:${maxRetries}`
);
}
const retryAfterMs = parseRetryAfter(
response.headers.get("retry-after")
);
const backoffCap = Math.min(
maxDelayMs,
baseDelayMs * 2 ** attempt
);
const jitterMs = Math.floor(Math.random() * backoffCap);
const delayMs = retryAfterMs ?? jitterMs;
console.warn(
`收到 429,第 ${attempt + 1} 次等待 ${delayMs}ms 后重试`
);
await sleep(delayMs);
}
throw new Error("请求失败");
}
مثال على الاستدعاء:
const response = await fetchWithRetry(
"https://api.example.com/v1/resources",
{
headers: {
Authorization: `Bearer ${process.env.API_TOKEN}`,
Accept: "application/json",
},
},
{
maxRetries: 3,
baseDelayMs: 1000,
maxDelayMs: 30_000,
}
);
if (!response.ok) {
const errorBody = await response.text();
throw new Error(`API 请求失败:${response.status} ${errorBody}`);
}
const data = await response.json();
console.log(data);
¶ عند إعادة محاولة طلبات POST، يجب أيضًا مراعاة قابلية التكرار
ليست كل الطلبات مناسبة لإعادة المحاولة التلقائية. عادةً ما تكون طلبات القراءة مثل GET وHEAD أسهل لإعادة المحاولة بأمان. بالنسبة إلى طلبات POST مثل إنشاء الطلبات، وخصم المدفوعات، وإرسال الرسائل، قد يكون العميل قد أرسل الطلب بنجاح بالفعل، لكنه لم يتلقَّ استجابة بسبب انقطاع الشبكة. يمكن أن تؤدي إعادة المحاولة المباشرة في هذه الحالة إلى عمليات مكررة.
إذا كانت المنصة تدعم ذلك، فيجب تعيين مفتاح قابلية التكرار لعمليات الكتابة:
curl -i -X POST "https://api.example.com/v1/orders" \
-H "Authorization: Bearer $API_TOKEN" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: order-20260331-0001" \
-d '{
"product_id": "prod_123",
"quantity": 1
}'
يتم تحديد اسم ترويسة الطلب ومدة صلاحية مفتاح قابلية التكرار من قبل المنصة المعنية، ويجب الرجوع إلى وثائق API المقابلة.
¶ قائمة التحقق لاستكشاف الأعطال في بيئة الإنتاج
¶ عند تلقي 401
- هل يحتوي الطلب على ترويسة مصادقة
- هل مخطط المصادقة مثل
Bearerصحيح - هل انتهت صلاحية Token أو تم إلغاؤه أو نسخه بشكل خاطئ
- هل يُستخدم مفتاح البيئة الصحيح
- هل قام الوكيل أو البوابة بحذف ترويسة المصادقة
- هل وقت العميل دقيق
- هل يمكن تحديث Token مرة واحدة بأمان
¶ عند تلقي 403
- هل يمتلك الـ Token نطاقات Scope المطلوبة
- هل يمتلك الحساب الحالي الدور المطلوب
- هل ينتمي المورد إلى المشروع أو المستأجر الحالي
- هل عنوان IP الصادر موجود في القائمة البيضاء
- هل يخضع لقيود المنطقة أو WAF أو سياسة الأمان
- هل يشير جسم الاستجابة بوضوح إلى الصلاحيات أو تحديد المعدل
- هل توجد معلومات عن تحديد المعدل في رؤوس الاستجابة
¶ عند تلقي 429
- هل تمت قراءة
Retry-After - هل تم التحقق من رؤوس الاستجابة المتعلقة بتحديد المعدل
- هل يُستخدم التراجع الأُسّي والاهتزاز العشوائي
- هل تم تعيين الحد الأقصى لعدد مرات إعادة المحاولة
- هل تم تقييد التزامن
- هل تم تخزين نتائج الاستعلامات المكررة مؤقتًا
- هل يمكن دمج الطلبات أو إرسالها على دفعات
- هل تم الوصول إلى حصة الباقة أو الحد الأعلى لاستخدام الحساب
¶ ما معلومات التشخيص التي يُنصح بتسجيلها؟
يُنصح بتسجيل وقت الطلب، واسم مضيف API والمسار، وطريقة HTTP، ورمز الحالة، ورمز خطأ الأعمال، وrequest-id أو trace-id، وRetry-After، والحصة المتبقية لتحديد المعدل ووقت إعادة التعيين، وعدد مرات إعادة المحاولة ووقت الانتظار الفعلي في السجلات.
لكن لا تسجل مفتاح API كاملًا، أو Access Token كاملًا، أو Refresh Token، أو كلمة مرور المستخدم، أو المعلومات الشخصية الحساسة في جسم الطلب.
¶ القاعدة النهائية للحكم
401: أصلح بيانات الاعتماد أولًا، ولا تُعد المحاولة باستخدام Token قديم.
403: أصلح الصلاحيات أو السياسة أولًا، ولا تكرر الطلب كما هو.
429: احترم وقت الانتظار، وتراجع، وخفّض السرعة، وقيّد التزامن.
رمز الحالة ليس سوى مدخل لاستكشاف الأخطاء وإصلاحها، وليس الإجابة الكاملة. الطريقة الموثوقة للتعامل هي الجمع بين رمز حالة HTTP، ورمز خطأ الأعمال في جسم الاستجابة، ورؤوس الاستجابة ذات الصلة، ووثائق المنصة، ومعرّف الطلب، وسجلات الخادم، لتحويل «خطأ الواجهة» إلى آلية هندسية قابلة للملاحظة والاستعادة والصيانة.

