دليل شامل لـ HTTP Status Codes
السلام عليكم ورحمة الله وبركاته
المقدمة
تخيل أنك تتصل بصديقك وتطلب منه شيئًا ما، بعد انتهاء المكالمة سيخبرك بنتيجة طلبك
هل نجح في تنفيذه ؟ أم فشل ؟ وإن فشل، لماذا ؟
هذا بالضبط ما تفعله الـ HTTP Status Codes
هي أرقام يرسلها الـ Server للـ Client لتوضيح نتيجة الطلب الذي قام به
فعندما ترسل طلبًا للـ Server سواء لإحضار بيانات أو إنشاء مستخدم جديد أو حذف مقالة
الـ Server لن يرد عليك ببيانات فقط، بل سيرفق معها رقم يوضح حالة الطلب
هل كل شيء تمام ؟ أم هناك مشكلة ؟ وما نوع هذه المشكلة ؟
لماذا نحتاج الـ Status Codes ؟
تخيل معي السيناريو التالي:
أنت كـ Frontend تريد إحضار بيانات مستخدم معين، فترسل طلبًا للـ API
الـ Server يرد عليك بهذه الرسالة فقط:
{
"message": "Error"
}
حسنًا، حدث خطأ... لكن ما هو الخطأ ؟
- هل المستخدم غير موجود ؟
- هل أنا غير مسجل في النظام ؟
- هل ليس لدي صلاحية للوصول لهذا المستخدم ؟
- هل الـ
Serverنفسه به مشكلة ؟ - هل أرسلت البيانات بشكل خاطئ ؟
أنت هنا لن تعرف أبدًا والـ Frontend لن يستطيع التعامل مع الخطأ بشكل صحيح
الآن تخيل أن الـ Server أرسل لك رقم 404 مع الرسالة:
// Status Code: 404
{
"status": "error",
"message": "User not found"
}
الآن أنت تعرف بالضبط أن المستخدم غير موجود
وتستطيع أن تعرض للمستخدم رسالة مناسبة مثل "عذرًا، هذا المستخدم غير موجود"
أو لو أرسل لك 401:
// Status Code: 401
{
"status": "error",
"message": "Please login first"
}
هنا تعرف أنك غير مسجل الدخول، فتقوم بتوجيه المستخدم لصفحة تسجيل الدخول
هذا هو جمال الـ Status Codes، كل رقم له معنى محدد ومتفق عليه
وهذا بدوره يسهل التواصل بين الـ Frontend والـ Backend بشكل كبير
هذه الأرقام تم الاتفاق عليها في بروتوكول الـ HTTP، وكل رقم له معنى محدد
وبعض الأرقام لم يتم الاتفاق على معنى لها حتى الآن وبقيت لاستخدامات مستقبلية
نحن هنا لنغطي أهم وأشهر هذه الأرقام التي ستحتاجها كـ Frontend أو Backend لفهم الـ RESTful API
تصنيف الـ Status Codes
تنقسم رموز الحالة إلى خمس فئات رئيسية، كل فئة تبدأ برقم معين
وهذا التقسيم يسهل عليك فهم طبيعة الرد حتى لو لم تكن تعرف الرقم بالتحديد
| الفئة | النطاق | المعنى |
|---|---|---|
| 1xx | 100-199 | Informational تم استلام الطلب وجاري المعالجة |
| 2xx | 200-299 | Success تم استلام الطلب وفهمه وقبوله بنجاح |
| 3xx | 300-399 | Redirection يجب اتخاذ إجراء إضافي لإكمال الطلب |
| 4xx | 400-499 | Client Error الطلب يحتوي على خطأ أو لا يمكن تنفيذه |
| 5xx | 500-599 | Server Error حدثت مشكلة غير متوقع في الـ Server |
فلو رأيت رقمًا يبدأ بـ 2 فاعلم أن الأمور على ما يرام
ولو رأيت رقمًا يبدأ بـ 4 فاعلم أن هناك خطأ من الـ Client
ولو رأيت رقمًا يبدأ بـ 5 فاعلم أن المشكلة من الـ Server نفسه
1xx رموز المعلومات - Informational
هذه الفئة نادرًا ما تتعامل معها بشكل مباشر في الـ RESTful API
هى أشبه برسائل داخلية بين الـ Client والـ Server أثناء عملية نقل البيانات ليخبر كل منهما الآخر بأنه على المسار الصحيح أو مستعد لاستقبال المزيد من البيانات
على أي حال لن أقوم بشرحها هنا لأنك لن تصادفها أو تحتاجها
وإن كنت متخصصًا جدًا وصادفت أنك تحتاج استخدامها أو فهمها فغالبًا ستبحث عنها لهدف محدد
وأنا شخصيًا لم أستخدمها في أي مشروع عملي لذلك فأنا ليست الشخص المناسب لشرحها هنا
2xx رموز النجاح - Success
هذه أهم فئة ستتعامل معها وأكثرها استخدامًا
عندما ترى رقمًا يبدأ بـ 2، اعلم أن طلبك تم بنجاح
200 OK
الأكثر شيوعًا واستخدامًا وييدل على أنه تم تنفيذ العملية بنجاح وسيرسل الـ Server بيانات كنتيجة للعملية في الـ Body الخاص بالـ Response
لنرى مثالًا عمليًا:
// طلب إحضار بيانات مستخدم
async function getUser() {
const response = await fetch("https://api.example.com/users/1");
const data = await response.json();
console.log(response.status); // 200
console.log(data); // بيانات المستخدم
}
الرد من الـ Server:
// Status Code: 200 OK
{
"status": "success",
"code": 200,
"data": {
"id": 1,
"name": "Ahmed",
"email": "ahmed@domain.com",
"age": 25
}
}
متى نستخدمها ؟
GET: عند إحضار بيانات بنجاح والبيانات موجودة في الـBodyPOST: عندما يقوم الـServerبتنفيذ عملية معينة دون إنشاء شيء ويريد إرجاع بيانات في الـBodyPUTأوPATCH: عند تعديل شيء ما أو القيام بعملية معينة وتريد إرجاع بعض البيانات في الـBodyDELETE: عند حذف شيء ما وتريد إرجاع بيانات العنصر المحذوف في الـBody
ملحوظة: ستجدني أكرر جملة وتريد إرجاع بيانات في الـBodyكثيرًا
بسبب أن الفرق بين200و204هو وجود بيانات في الـBodyمن عدمه
فكلاهما يستخدمان لنفس الشيء لكن الفرق أن200يخبرك بأن العملية نجحت مع وجود بيانات في الـBodyالخاص بالـResponse204يخبرك بأن العملية نجحت ولكن لا توجد بيانات في الـBodyالخاصة بالـResponse
201 Created
تم إنشاء بيانات جديدة بنجاح
تُستخدم غالبًا مع POST عند إضافة عنصر جديد لقاعدة البيانات
الفرق الجوهري بين 200 و 201:
- الـ
200تقول: "تم تنفيذ طلبك بنجاح" - الـ
201تقول: "تم إنشاء شيء جديد"
لنرى مثالًا عمليًا للـ 201 Created:
// طلب إنشاء مستخدم جديد
async function createUser() {
const response = await fetch("https://api.example.com/users", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
name: "Ali",
email: "ali@domain.com",
age: 30,
}),
});
console.log(response.status); // 201
}
الرد من الـ Server:
// Status Code: 201 Created
{
"status": "success",
"code": 201,
"message": "User created successfully",
"data": {
"id": 25,
"name": "Ali",
"email": "ali@domain.com",
"age": 30,
"createdAt": "2024-12-07T10:30:00Z"
}
}
لاحظ أن الـ Server أضاف معلومات إضافية مثل الـ id و createdAt
هذه معلومات لم يرسلها الـ Frontend لكن الـ Server أنشأها تلقائيًا
بمعنى أنه من المهم أن يرسل لك الـ Server البيانات الجديدة التي تم إنشاؤها في الـ Body
لأنها قد تحتوي على معلومات زائدة ومهمة لم تكن من ضمن البيانات التي أرسلتها للـ Server
نستخدم 201 Created في الحالات التالية:
POST: عند إنشاء بيانات جديدة بنجاح مثل مستخدم جديد، مقالة جديدة، إلخ ...PUT: إذا كان العنصر المراد تعديله غير موجود وتم إنشاؤه بدلًا من ذلك
ملحوظة: عند إرسال201، يُفضل إضافةheaderباسمLocationيحتوي على رابط الـResourceالجديد الذي تم إنشاؤه
HTTP/1.1 201 Created
Location: https://api.example.com/users/25
202 Accepted
هذا الرمز مميز ومختلف عن البقية
بحيث أنه يرمز إلى أن الطلب تم استلامه بنجاح، لكن لم يُنفذ بعد، وهى حاليًا تُنفذ في الخلفية
بمعنى أن الـ Server استلم الطلب ويؤكد استلامه، لكنه لم ينتهى من تنفيذ العملية بعد
لماذا قد نحتاج هذا ؟
تخيل إرسال 10000 بريد إلكتروني للمشتركين
هل من المنطقي أن ينتظر الـ Frontend حتى تُرسل كل هذه الرسائل ؟ بالطبع لا
العمليات التي تستغرق وقتًا طويلًا مثل هذه، من الأفضل تنفيذها في الخلفية وخصوصًا إذا كان الـ Client لا يحتاج لانتظار النتيجة
بدلًا من ذلك، الـ Server يستلم الطلب ويرد بـ 202 ليؤكد الاستلام ويبدأ التنفيذ في الخلفية
// إرسال نشرة بريدية لكل المشتركين
async function sendNewsletter(subject, content) {
const response = await fetch("https://api.example.com/newsletter/send", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
subject,
content,
}),
});
console.log(response.status); // 202
}
الرد من الـ Server:
// Status Code: 202 Accepted
{
"status": "accepted",
"code": 202,
"message": "Newsletter is being sent to 10,000 subscribers"
}
ملحوظة: الـ202لا تعني أن العملية نجحت، بل تعني أنها بدأت
قد تفشل العملية لاحقًا أو قد تنجح، فالـ202تعني فقط أن الطلب تم استلامه وبدأ التنفيذ لا أكثر ولا أقل
أحيانًا قد يحتاج المستخدم إلى معرفة نتيجة العملية التي بدأت في الخلفية
في هذه الحالة يمكن للـ Server أن يرسل notification للمستخدم عند انتهاء العملية ويعلمه بالنتيجة سوواء بالنجاح أو الفشل
أو يمكن أن يتم استخدام نظام webhooks أو websockets لإعلام الـ Client بالنتيجة
أو أي وسيلة أخرى مناسبة حسب طبيعة المشروع
204 No Content
تم تنفيذ العملية بنجاح، لكن لا توجد بيانات لإرجاعها
ما الفرق بينها وبين 200 ؟
- الـ
200تقول: "نجحت العملية، وسأرسل لك البيانات الناتجة" - الـ
204تقول: "نجحت العملية، ولا يوجد شيء لأرسله لك"
المثال الأشهر هو حذف عنصر:
// حذف مستخدم
async function deleteUser(userId) {
const response = await fetch(`https://api.example.com/users/${userId}`, {
method: "DELETE",
});
console.log(response.status); // 204
}
عندما تحذف شيئًا، ماذا سترجع ؟ الشيء المحذوف ؟
غالبًا الإجابة لا، لذلك الـ 204 هي الخيار الأمثل هنا في حالة عندما لا تحتاج لإرجاع أي بيانات في الـ Body الخاص بالـ Response
متى تستخدمها ؟
DELETE: عند حذف شيء ما بنجاح ولا تريد إرجاع بيانات العنصر المحذوفPUTأوPATCH: عند تعديل شيء ما بنجاح ولا تريد إرجاع البيانات المعدلةPOST: عند تنفيذ عملية معينة بنجاح ولا توجد بيانات لإرجاعها مثل تسجيل الخروج
كما قلت الفرق الوحيد بين 200 و 204 هو وجود بيانات في الـ Body من عدمه
بالتالي لو أردنا إرجاع البيانات المحذوفة مع الـ DELETE ففي هذه الحالة سنرسل 200 وليس 204
3xx رموز إعادة التوجيه - Redirection
هذه الفئة تخبر الـ Client بأن الـ Resource المطلوب موجود في مكان آخر
أو أنه يحتاج اتخاذ إجراء إضافي للوصول إليه
301 Moved Permanently
الـ Resource انتقل بشكل دائم لعنوان جديد
هذا يعني أن الرابط القديم لم يعد صالحًا ويجب استخدام الرابط الجديد دائمًا
لنفترض أن موقعك كان على http://old-site.com وانتقل إلى https://new-site.com
بالتالي عندما يحاول المستخدم الوصول لـ http://old-site.com/articles/5
سيتم تحويله تلقائيًا إلى https://new-site.com/articles/5 وسيجد الـ Status Code يساوي 301 في الـ Response
302 Found
الـ Resource انتقل بشكل مؤقت لعنوان آخر
هذا يعني أن الرابط الأصلي لا يزال صالحًا ويجب استخدامه في المستقبل
لنفترض أن موقعك تحت الصيانة وتريد توجيه المستخدمين لموقع أخر مؤقتًا أو لصفحة موقوف للصيانة
هنا عندما يحاول المستخدم الوصول إلى موقعك سيجد نفسه يتم توجيهه إلى موقع أخر أو رابط أخر مؤقتًا
مع Status Code يساوي 302 في الـ Response
ليس شرطًا أن يكون الموقع الآخر هو موقعك، قد يكون صفحة صيانة داخل موقعك نفسه
أو أنك تدخل إلى صفحة منتج ما، لكن المنتج غير متوفر حاليًا فتوجهك لصفحة أخرى مؤقتًا
303 See Other
يُستخدم لتوجيه الـ Client لرابط آخر باستخدام GET بعد تنفيذ الطلب بنجاح
تخيل معي أن المستخدم يقوم بإرسال طلب شراء لمنتج معين
هنا لدينا HTML Form يقوم المستخدم بملئه ثم يضغط على زر إرسال الطلب
هنا سيقوم الـ Client بإرسال طلب POST إلى الـ Server
POST /api/orders
{ "product": "laptop", "quantity": 1 }
هنا سيقوم الـ Server بإنشاء الطلب بنجاح ويخزنه في جدول الـ Orders في قاعدة البيانات بـ id معين وليكن 12345
هنا نحتاج من الـ Client أن يوجه المستخدم لصفحة تعرض له تفاصيل الطلب الخاص به
لكن المشكلة هنا ليست فقط أن الـ Client لا يعرف الـ id الخاص بالطلب الجديد
وإنما المشكلة الأهم هي تجنب إعادة إرسال طلب POST مرة أخرى في حال قام المستخدم بتحديث الصفحة، أي قام بـ Refresh للصفحة
فلو قام الـ Server بإرجاع 201 Created مع بيانات الطلب الجديد في الـ Body ثم قام المستخدم بتحديث الصفحة
هنا سيقوم المتصفح بإعادة إرسال طلب POST مرة أخرى، بالتالي سيؤدي إلى إنشاء طلب شراء مكرر
لذلك يقوم الـ Server بإرجاع 303 See Other مع Location في الـ headers
يشير إلى رابط صفحة تفاصيل الطلب الجديد:
HTTP/1.1 303 See Other
Location: /orders/12345
الميزة الأساسية في 303 See Other أنه يفرض على المتصفح أن يقوم بطلب جديد من نوع GET
حتى وإن كان الطلب الأصلي POST, بالتالي سيقوم المتصفح بطلب GET /orders/12345 لعرض صفحة تأكيد الطلب
وأي تحديث للصفحة بعد ذلك سيعيد تنفيذ طلب GET فقط دون إعادة إرسال طلب الشراء مرة أخرى
ما شرحناه للتو هو مشكلة شائعة في المشاريع التي تقوم على الـ Server Side Rendering وتستخدم الـ HTML Forms
والحل هو اسلوب يسمى Post/Redirect/Get (PRG)
وهو كما يوحي فهو يقوم بثلاث خطوات:
Post: المستخدم يرسل طلبPOSTلإنشاء شيء ماRedirect: الـServerيعيد توجيه المستخدم إلى صفحة أخرى باستخدام303 See OtherGet: المتصفح يقوم بعمل طلبGETللصفحة الجديدة في حال حدوثRefreshلصفحة الـHTML Form
ملحوظة: غالبًا في المشاريع التي تعتمد على الـRESTful APIبشكل كامل يفضل استخدام201 Createdبدلًا من303 See Other
أما إذا كان المشروع على نفس الـDomain/Originويستخدم الـHTML FormsوالـBackendهوServer Side Renderingيقوم بعملRenderingللصفحات و يقوم بعملRedirectingللصفحات فهنا يكون استخدام303 See Otherهو الأنسب لتطبيق فكرة الـPost/Redirect/Get Pattern
304 Not Modified
الـ Resource لم يتغير منذ آخر مرة طلبته
هذا الرمز يُستخدم مع الـ Caching غالبًا
كيف يعمل ؟
- الـ
Clientيفتح صفحة المنتج لأول مرة - يحصل على بيانات المنتج مع
Status Codeيساوي200
ويخزن نسخة من هذه البيانات في الـCacheمن ناحية الـClientأو من الـProxy ServerمثلCDN - في المرة التالية التي يفتح فيها نفس الصفحة، يرسل طلبًا مع
headerيسمىIf-Modified-SinceأوETag
ليخبر الـServerبآخر نسخة مخزنة لديه - إذا لم يتغير المنتج، يرد الـ
ServerبـStatus Codeيساوي304 Not Modified
مما يخبر الـClientبأنه يمكنه استخدام النسخة المخزنة في الـCacheدون الحاجة لعملQueryجديد على قاعدة البيانات أو إعادة إرسال البيانات من الـServer - إذا تغير المنتج، يرد الـ
Serverبـ200 OKمع البيانات الجديدة
307 Temporary Redirect
هذا الرمز يشبه 302 إلى حد كبير، لكن مع فرق مهم جدًا جعله بديل أفضل عن 302 في كثير من الحالات
الـ 307 Temporary Redirect يعني أن الـ Resource انتقل بشكل مؤقت إلى عنوان آخر
مع الحفاظ على نفس الـ HTTP Method دون تغييره
بمعنى أننا في 302 على سبيل المثال لو أرسلنا POST وتم إعادة التوجيه
فسيتحول الـ Client الطلب إلى GET في الرابط الجديد
أما مع 307، فلو أرسلنا POST سيتم إعادة إرسال POST في الرابط الجديد
على عكس 302 الذي يغير الـ Method إلى GET
308 Permanent Redirect
هذا الرمز هو النسخة الحديثة من 301 Moved Permanently
وهو يقوم بنفس الشيء لكن مع نفس الفرق الجوهري الذي بين 302 و 307
الـ 308 Permanent Redirect يعني أن الـ Resource انتقل بشكل دائم إلى عنوان جديد
مع الحفاظ على نفس الـ HTTP Method دون تغييره
بمعنى أننا في 301 على سبيل المثال لو أرسلنا POST وتم إعادة التوجيه
فسيتحول الـ Client الطلب إلى GET في الرابط الجديد
أما مع 308، فلو أرسلنا POST سيتم إعادة إرسال POST في الرابط الجديد
على عكس 301 الذي يغير الـ Method إلى GET
4xx رموز أخطاء من الـ Client
هذه الفئة تخبر الـ Client بأن هناك خطأ من ناحيته
إما أن الطلب غير مفهوم أو لا يمكن تنفيذه
وهذه الفئة من أهم الفئات التي يجب أن تفهمها جيدًا
لأن استخدام الرمز الصحيح يسهل على الـ Frontend التعامل مع الأخطاء
400 Bad Request
الطلب نفسه غير صحيح أو غير مفهوم للـ Server
قد يكون هناك خطأ في صيغة البيانات أو في شكل الطلب بحيث لا يستطيع الـ Server تفسيره
على سبيل المثال:
- إذا كان الـ
JSONغير صحيح من ناحية الصياغة أي أنهSyntax Error
مثل وجود فاصلة زائدة أو نقص في الأقواس - أو أن الـ
Serverيتوقع بيانات معينة مثلname،email،password
لكن الـClientأرسل جزءًا فقط منها بشكل غير كافٍ لفهم الطلب - أو أن نوع البيانات المرسلة غير قابل للفهم أصلًا
مثل أن الـ
Serverيتوقعageكرقم وليكن25
لكن الـClientأرسل نص "خمسة وعشرون"
مثال للرد من الـ Server:
// Status Code: 400 Bad Request
{
"status": "error",
"code": 400,
"message": "Invalid request body",
"errors": [
{
"field": "email",
"message": "Email is required"
},
{
"field": "age",
"message": "Age must be a number"
}
]
}
لاحظ أن الـ Server الجيد يوضح بالتفصيل ما هي المشكلة
ولا يكتفي بإرسال Bad Request فقط ويترك الـ Client يخمن بنفسه
غالبًا ما يستخدم 400 كرمز عام وافتراضي يحدث لأي خطأ من جهة الـ Client
لكن من الأفضل استخدام رموز أكثر تحديدًا مثل 401، 403، 404، 422 حسب نوع الخطأ
401 Unauthorized
المستخدم غير معروف للـ Server
بالتالي يجب اعادة تسجيل الدخول أو إرسال Token صالح
أو إرسال أي وسيلة تعرف الـ Server بهوية المستخدم
غالبًا ما يستخدم هذا الرمز مع الـ APIs التي تعتمد على الـ Token أو الـ JWT
ويحدث عندما لا يرسل الـ Client الـ Token أو يرسل Token غير صحيح أو منتهي الصلاحية
بالتالي الـ Server لا يستطيع التحقق من هوية المستخدم
فيقوم الـ Server بإرسال 401 مع رسالة توضح أنه يجب تسجيل الدخول أولًا
// Status Code: 401 Unauthorized
{
"status": "error",
"code": 401,
"message": "Authentication required. Please login to access this resource."
}
بالتالي سيقوم الـ Client بتوجيه المستخدم لصفحة تسجيل الدخول لإعادة إنشاء Token جديد
403 Forbidden
المستخدم معروف للـ Server لكن ليس لديه صلاحية للوصول لهذا الـ Resource
بمعنى أن الهوية صحيحة لكن الصلاحيات غير كافية
// Status Code: 403 Forbidden
{
"status": "error",
"code": 403,
"message": "You do not have permission to access this resource."
}
الفرق الجوهري بين 401 و 403:
401: مشكلة هوية، بمعنى أن المستخدم غير معروف403: مشكلة صلاحيات، بمعنى أن المستخدم معروف لكن ممنوع عليه الوصول لهذا الـResource
ملحوظة: لمزيد من التوضيح يمكن قراءة الفرق بين الـ 401 و 403 في الـ RESTful API
أحيانًا يتم إرسال 404 Not Found بدلًا من 403 Forbidden لأسباب أمنية لكي لا نعطي معلومات عن وجود الـ Resource من عدمه
مثلاً لو حاول مستخدم عادي الوصول إلى صفحة إدارة المستخدمين
لماذا نعطيه معلومة بأن الصفحة موجودة لكنه ممنوع من الوصول لها ؟
لأننا لو أرسلنا له 403 Forbidden فسيعرف أن الصفحة موجودة لكنه ممنوع من الوصول لها
لذلك نرسل له 404 Not Found ليعتقد أن الصفحة غير موجودة أصلًا
وفي حالة أنه مستخدم يحاول اختراق النظام فأننا نمنعه من معرفة وجود الصفحة من عدمه
404 Not Found
الـ Resource المطلوب غير موجود
لم يتم العثور على البيانات المطلوبة في الـ Server
وغالبًا ما يحدث هذا عندما يكون الـ endpoint غير صحيح أو الـ ID غير موجود في قاعدة البيانات
مثل أن يحاول المستخدم الوصول لصفحة أو منتج غير موجود
// Status Code: 404 Not Found
{
"status": "error",
"code": 404,
"message": "User with id 99999 not found"
}
أيضًا الـ 404 Not Found قد تشير إلى أن الـ resource ليس متاحًا حاليًا
لكنه قد يكون موجودًا في المستقبل أو أنه موجود في مكان آخر
أو أنك أنه محذوف بشكل مؤقت أو أنك لا تملك صلاحية الوصول له
وذكرنا أننا قد نرسل 404 Not Found بدلًا من 403 Forbidden لأسباب أمنية
405 Method Not Allowed
الـ HTTP Method المستخدم غير مسموح لهذا الـ endpoint
لنفترض أن الـ endpoint الخاص بالمستخدمين يقبل GET و POST فقط
لكن المطور قام بإرسال طلب بـ DELETE إلى هذا الـ endpoint
هنا سيرد الـ Server بـ 405 Method Not Allowed
// Status Code: 405 Method Not Allowed
{
"status": "error",
"code": 405,
"message": "Method DELETE not allowed on /api/users",
"allowedMethods": ["GET", "POST"]
}
409 Conflict
الطلب يتعارض مع بيانات موجودة مسبقًا
بمعنى أن البيانات المرسلة صحيحة لكنها تتعارض مع شيء موجود في قاعدة البيانات
تخيل أنك تحاول تسجيل حساب جديد ب بريد إلكتروني موجود مسبقًا
البريد إلكتروني قد يكون صحيح دون أي خطأ، لكن التعارض يكمن في أنه مستخدم بالفعل
// طلب تسجيل مستخدم جديد
async function registerUser() {
const response = await fetch("https://api.example.com/register", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
name: "Ahmed",
email: "ahmed@domain.com",
password: "123456",
}),
});
console.log(response.status); // 409
}
الرد من الـ Server:
// Status Code: 409 Conflict
{
"status": "error",
"code": 409,
"message": "Email already exists",
"field": "email",
"suggestion": "Try logging in or use a different email"
}
هذا الرمز يناسب أي تعارض، مثل محاولة إنشاء حساب مكرر أو تفعيل حساب مفعل بالفعل
أو حتى في حالة race condition مثل حجز آخر تذكرة متاحة من قبل مستخدمين في وقت واحد
فأول مستخدم يحصل على التذكرة، والآخر يحصل على 409 Conflict
410 Gone
الـ Resource كان موجودًا لكنه حُذف نهائيًا ولا يوجد أي إمكانية لاسترجاعه
وهو يشبه 404 Not Found لكن مع فرق جوهري:
404 Not Found: يعني أن الـResourceغير موجود حاليًا، لكنه قد يكون موجودًا في المستقبل
أو أنه متواجد في مكان آخر أو يوجد وسيلة لاسترجاعه أو حذف بشكل مؤقت
ولا يوضح إذا كان الـResourceكان موجودًا في السابق أم لا410 Gone: يعني أن الـResourceحُذف نهائيًا ولن يعود أبدًا مهما حصل
وأيضًا يوضح أن هذا الـResourceكان موجودًا في السابق لكنه الآن غير متاح
تخيل أن مستخدمًا يحاول الوصول إلى مقالة قديمة تم حذفها نهائيًا من الموقع
أو حساب مستخدم تم حذفه تمامًا من قاعدة البيانات
// طلب إحضار مقالة محذوفة
async function getArticle() {
const response = await fetch(
"https://api.example.com/articles/old-article-2020",
);
console.log(response.status); // 410
}
الرد من الـ Server:
// Status Code: 410 Gone
{
"status": "error",
"code": 410,
"message": "This article has been permanently deleted",
"deletedAt": "2024-01-15T10:30:00Z"
}
هذا يوضح لنا أن المقالة كانت موجودة في السابق لكنها حُذفت نهائيًا، ولا توجد أي طريقة لاسترجاعها
وأيضًا لدواعي أمنية فقد تجد من يستخدم 404 Not Found بدلًا من 410 Gone لعدم إعطاء معلومات أن هذا الـ Resource كان موجودًا في السابق أم لا
لأن الـ 410 Gone تؤكد أن هذا الـ Resource كان موجودًا في السابق
أما الـ 404 Not Found لا تؤكد أن هذا الـ Resource كان موجودًا أم لا
415 Unsupported Media Type
نوع البيانات المرسلة غير مدعوم
الـ Server لا يقبل هذه الصيغة من البيانات، مثل إرسال XML بينما يتوقع JSON
أو أن الموقع يستقبل صورًا بصيغ محددة فقط وأرسلت صيغة غير مدعومة
تخيل معين أن الـ Server يستطيع أن يقوم بعمل import لبيانات وهو يستقبل ملف بصيغة من صيغ الـ excel فقط مثل xlsx
وأنت قمت بإرسال ملف بصيغة csv، هنا سيرد عليك بـ 415 Unsupported Media Type
// طلب رفع ملف بصيغة غير مدعومة
async function importData(file) {
const formData = new FormData();
formData.append("file", file);
const response = await fetch("https://api.example.com/data/import", {
method: "POST",
body: formData,
});
console.log(response.status); // 415
}
الرد من الـ Server:
// Status Code: 415 Unsupported Media Type
{
"status": "error",
"code": 415,
"message": "Unsupported Media Type",
"supportedTypes": ["xlsx"]
}
هذا يحدث أيضًا في رفع الملفات، مثل رفع فيديو في مكان يقبل صور فقط
الـ Server يفهم الطلب لكنه يرفض الصيغة، ويتم إخبار الـ Client بالصيغ المدعومة
422 Unprocessable Entity
البيانات وصلت بشكل صحيح لكنها غير صالحة بالنسبة للمشروع أو بالنسبة لشروط الـ Business Logic
بمعنى أن القيم والبيانات صحيحة ويمكن أن تقبل في ظروف أخرى، أو في مشاريع أخرى بدون مشاكل بحسب الـ Business Requirements
أو يمكن أن البيانات سليمة من ناحية الصياغة لكن لا تتوافق مع قواعد التحقق Validation Rules
لأن القيم غير منطقية ولا يمكن قبولها في النظام الخاص بنا
مثل أننا نقبل أسعار المنتجات كأرقام موجبة فقط، لكن تم إرسال سعر سالب
أوأننا استقبلنا اسم منتج يقل عن 3 حروف، أو بريد إلكتروني بصيغة غير صحيحة
وهكذا ...
// طلب إنشاء مستخدم مع بيانات غير منطقية
async function createUser() {
const response = await fetch("https://api.example.com/users", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
name: "a",
email: "not-an-email",
age: -5,
password: "123",
}),
});
console.log(response.status); // 422
}
الرد من الـ Server:
// Status Code: 422 Unprocessable Entity
{
"status": "error",
"code": 422,
"message": "Validation failed",
"errors": [
{
"field": "name",
"message": "Name must be at least 3 characters long"
},
{
"field": "email",
"message": "Invalid email format"
},
{
"field": "age",
"message": "Age must be a positive number"
},
{
"field": "password",
"message": "Password must be at least 8 characters"
}
]
}
هذا الرمز مثالي لأخطاء التحقق وهى الـ Validation Errors
لاحظ أن الـ Server كان بإمكانه تخزين هذه البيانات في قاعدة البيانات كما هى دون مشاكل من ناحية الصياغة
لكن هنا ما يحكمنا هو الـ Business Logic والـ Validation Rules الخاصة بالمشروع والتي تمنع قبول هذه القيم
لذالك نستخدم 422 Unprocessable Entity لإبلاغ الـ Client بأن البيانات غير صالحة لهذا المشروع
بعض الناس يستخدمون 400 بدلًا منه، لكن 422 يعد الأدق لأن البيانات صحيحة من ناحية الصياغة ومفهومة، لكن لا يمكن قبولها بسبب قواعد الـ Validation أو الـ Business Logic
قد يختلط على البعض الفرق بين 400 و 422، لكن يمكننا التمييز بينهما كالتالي:
400 Bad Request: البيانات غير صحيحة في الصيغة أو غير مفهومة من الأصل
ويمكننا اختصار الأمر في جملة وهى أن الـServerلم يستطع فهم الطلب حتى يعالجه من الأساس- الـ
JSONالخاصة بالـPayloadغير صالح أو غير مكتمل بشكل يمنع الـServerمن فهمه - حقول مفقودة ضرورية مثل عدم إرسال
emailأوpassword - أنواع بيانات غير قابلة للقراءة مثل نص بدل رقم
- الـ
422 Unprocessable Entity: البيانات صحيحة من ناحية الصياغة ومفهومة، لكن لا يمكن قبولها بسبب قواعد الـValidationأو الـBusiness Logic
أي أن الـServerفهم الطلب لكنه ويمكنه معالجته لكنه يرفض ذلك بسبب الشروط المحكومة والمفروضة عليه- البيانات لا تتوافق مع قواعد وشروط المشروع
- البيانات لا تتوافق مع متطلبات الـ
Business - البيانات لا تتوافق مع شروط وقواعد الـ
Validation
ولا ننسى أيضًا أن الـ 400 يستخدم كخطأ عام لأي مشكلة من جهة الـ Client دون تخصيص
لكن كما قلنا من الأفضل استخدام رموز أكثر تحديدًا مثل 401، 403، 404، 422 حسب نوع الخطأ
ويعد الـ 422 هو الأنسب لأخطاء التحقق الخاصة بالـ Validation على البيانات أو من متطلبات الـ Business
429 Too Many Requests
يستخدم عندما يتم إرسال عدد كبير جدًا من الطلبات في فترة زمنية قصيرة
بالتالي ستجد أن الـ Server يرفض المزيد من الطلبات مؤقتًا لحماية نفسه من الضغط الزائد
تخيل مستخدمًا يحاول تسجيل الدخول بكلمات مرور خاطئة عدة مرات في فترة قصيرة
بعد 5 محاولات، ستجد أن الـ Server يمنع المستخدم من المحاولة مرة أخرى لمدة زمنية معينة
// محاولة تسجيل دخول متعددة
async function login() {
const response = await fetch("https://api.example.com/login", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
email: "ahmed@domain.com",
password: "wrong6",
}),
});
console.log(response.status); // 429
}
الرد من الـ Server:
// Status Code: 429 Too Many Requests
{
"status": "error",
"code": 429,
"message": "Too many login attempts. Please try again later."
}
هذا الرمز مهم جدًا في حماية الـ API من الهجمات مثل Brute Force أو DDoS
وهى أنواع من وسائل الهجوم التي تعتمد على إرسال عدد كبير من الطلبات في وقت قصير
فمثلًا تخيل شخص قام بعمل script يرسل آلاف الطلبات في الثانية لمحاولة اختراق النظام
أو لمحاولة سرقة حسابات المستخدمين عن طريق تجربة كلمات مرور كثيرة في وقت قصير
بالتالي يطبق الـ Server مفهوم الـ Rate Limiting ليحد من عدد الطلبات المسموح بها في فترة زمنية معينة
مثل السماح بـ 100 طلب في الدقيقة لكل مستخدم أو لكل عنوان IP
ويمكن تعديل هذه القيم حسب الحاجة
ويمكنه حظر مستخدم معين مؤقتًا إذا تجاوز الحد المسموح به
أو حذفه نهائيًا إذا استمر في المحاولة
لدواعي أمنية لا يعطي الـ Server تفاصيل أكثر عن الحد المسموح به أو مدة الحظر
ستجده يقول لك Please try again later فقط دون تحديد وقت معين
وهذه من باب عدم إعطاء معلومات إضافية قد يستغلها المهاجمون
5xx رموز أخطاء من الـ Server
هذه الفئة تخبر الـ Client بأن هناك خطأ من ناحية الـ Server
إما أن الـ Server غير قادر على التعامل مع الطلب أو حدث خطأ داخلي أثناء المعالجة
وغالبًا ما يكون خطأ غير متوقع لم يتم عمل له حساب بشكل صحيح
عندما يظهر رقم يبدأ بـ 5، فهذا يعني أن الـ Server نفسه به مشكلة
وغالبًا لا يوجد شيء يمكن للـ Frontend فعله سوى إظهار رسالة خطأ للمستخدم ويجب أن تكون رسالة عامة وغير تقنية مثل "حدث خطأ غير متوقع، يرجى المحاولة لاحقًا"
لذلك إن كنت مطور Frontend، ووجدت رمز خطأ يبدأ بـ 5 فأرسل رسالة إلى صديقك مطور Backend
وإن كانت المشكلة ظهرت في الـ Production فأدعو له بالتوفيق في إيجاد حل سريع أو في إيجاد فرصة عمل جديدة، أيهما أقرب
500 Internal Server Error
الطلب نفسه صحيح لكن حدث خطأ داخلي غير متوقع في الـ Server
قد يكون هناك خطأ في الكود أو في الاتصال بقاعدة البيانات بحيث لا يستطيع الـ Server إكمال العملية
على سبيل المثال:
- هناك خطأ في الكود البرمجي أدى إلى تعطل العملية مثل قسمة على صفر أو تجاوز الذاكرة المسموح بها
- هناك
Exceptionلم يتم التعامل معه مثل محاولة الوصول إلى متغير داخلobjectغير موجود أو قيمتهnull - الـ
Serverيحاول الاتصال بقاعدة البيانات لكن الاتصال فشل لسبب ما - ... وغيرها من الأخطاء الغير متوقعة
مثال للرد من الـ Server:
// Status Code: 500 Internal Server Error
{
"status": "error",
"code": 500,
"message": "Something went wrong on our end"
}
لاحظ أن الـ Server الجيد يوضح رسالة عامة للمستخدم دون تفاصيل حساسة
غالبًا ما يستخدم 500 كرمز عام وافتراضي لأي خطأ داخلي غير متوقع في الـ Server
مثله مثل الـ 400 من جهة الـ Client
غالبًا ما يكون من الصعب تحديد السبب الدقيق للخطأ من جهة الـ Client أو حتى من جهة الـ Backend
لذلك يجب على مطور الـ Backend تسجيل أي خطأ غير متوقع داخل ملفات الـ logs مع تخزين كل البيانات اللازمة
لكي يتمكن من تتبع المشكلة وحلها في حال عدم فصله من الشركة بعد
501 Not Implemented
الميزة أو الخاصية أو الصفحة المطلوبة غير مدعومة أو لم تُنفذ بعد في الـ Server
وسيتم تنفيذها في المستقبل أو أنها غير مدعومة نهائيًا
غالبًا ما يستخدم هذا الرمز مع الـ API التي لا تزال قيد التطوير
ويحدث عندما يكون الـ endpoint موجود لكن الكود الخاص به لم يكتب بعد
بالتالي الـ Server يعرف الطلب لكنه لا يستطيع تنفيذه حاليًا
فيقوم الـ Server بإرسال 501 مع رسالة توضح أن الميزة قادمة قريبًا
// Status Code: 501 Not Implemented
{
"status": "error",
"code": 501,
"message": "This feature is not implemented yet. Stay tuned!"
}
بالتالي سيقوم الـ Client بإظهار رسالة للمستخدم تفيد بأن الميزة غير متوفرة بعد
502 Bad Gateway
تخيل أنك لديك مدونة جميلة وقمت برفعها على Cloudflare أو استخدمت Nginx
وفي هذه الحالة فإن Nginx أو Cloudflare يعملان كـ Reverse Proxy أو Gateway بين المستخدم والـ Server الذي يستضيف المدونة
في حالة حدوث مشكلة في الاتصال بين الـ Reverse Proxy والـ Server الأساسي الخاص بالمدونة
فإن الـ Reverse Proxy سيرد على المستخدم بـ 502 Bad Gateway
لأنه لا يستطيع الوصول إلى الـ Server الخاص بالمدونة
503 Service Unavailable
عند استخدام Cloudflare أو Nginx كـ Reverse Proxy للمدونتك الجميلة
فإن الـ Reverse Proxy يقوم بتوجيه الطلبات إلى الـ Server الذي يستضيف مدونتك
وقلنا أنه في حالة حدوث مشكلة في الاتصال بين الـ Reverse Proxy والـ Server الخاص بالمدونة
سيقوم الـ Reverse Proxy بإرجاع 502 Bad Gateway
لكن في بعض الأحيان يكون الـ Server متاحًا لكن غير قادر على استقبال أو معالجة أي طلبات جديدة
هذا قد يحدث عندما يكون الـ Server الأساسي في وضع صيانة مؤقتة، أو يعاني من ضغط وحمل زائد، أو يمر بعملية Restart داخلية تمنعه من قبول الطلبات في تلك اللحظة
وعندما يحاول الـ Reverse Proxy إرسال الطلب ولا يحصل على استجابة تؤكد أن الـ Server الأساسي قادر على العمل، فإنه يعتبر أن الخدمة غير متاحة حاليًا
في هذه الحالة يقوم الـ Reverse Proxy بإرجاع كود 503 Service Unavailable
وهو يشير إلى أن الـ Server الأساسي موجود لكنه غير قادر على معالجة الطلب الآن، وغالبًا يمكن للمستخدم المحاولة مرة أخرى لاحقًا
504 Gateway Timeout
أظن أنك بمجرد قرأت كلمة Timeout فهمت المغزى من الرمز ومتى يستخدم
عند مرور الطلب عبر الـ Reverse Proxy ويقوم بتحويله إلى الـ Server الأساسي الخاص بالمدونة
ثم ينتظر الـ Reverse Proxy وقتًا طويلًا للحصول على استجابة من الـ Server الأساسي
ففي هذه الحالة يقوم الـ Reverse Proxy بإرسال 504 Gateway Timeout
سواء بسبب أن الـ Server الأساسي الخاص بالمدونة استغرق وقتًا أطول من الحد المسموح به للرد أو بسبب بطء شديد في الاستجابة
جدول لتلخيص رموز الـ HTTP Status
| الرمز | الفئة | الاسم بالإنجليزية | الوصف والملخص |
|---|---|---|---|
| 200 | Success | OK | تم تنفيذ الطلب بنجاح، ويحتوي الرد على بيانات في الـ Body |
| 201 | Success | Created | تم إنشاء Resource جديد بنجاح |
| 202 | Success | Accepted | تم استلام الطلب وبدء معالجته، لكن التنفيذ لم يكتمل بعد، وعادةً ما تُنفَّذ العملية في الخلفية |
| 204 | Success | No Content | تم تنفيذ الطلب بنجاح، ولا يحتوي الرد على بيانات في الـ Body |
| 301 | Redirection | Moved Permanently | الـ Resource انتقل إلى عنوان جديد بشكل دائم، وقد يؤدي ذلك إلى تغيير الـ Method إلى GET |
| 302 | Redirection | Found | الـ Resource انتقل إلى عنوان جديد بشكل مؤقت، وقد يؤدي ذلك إلى تغيير الـ Method إلى GET |
| 303 | Redirection | See Other | توجيه العميل لرابط آخر باستخدام GET بعد نجاح عملية POST |
| 304 | Redirection | Not Modified | الـ Resource لم يتغير منذ آخر طلب، ويجب على العميل استخدام النسخة المخزنة في الـ Cache |
| 307 | Redirection | Temporary Redirect | الـ Resource انتقل بشكل مؤقت لعنوان جديد مع الحفاظ على الـ Method |
| 308 | Redirection | Permanent Redirect | الـ Resource انتقل بشكل دائم لعنوان جديد مع الحفاظ على الـ Method |
| 400 | Client Error | Bad Request | الطلب غير صحيح، غير مفهوم، أو به خطأ في الصياغة مثل Syntax Error أو يعبر على أي خطأ في الطلب بشكل عام وهو الخيار الافتراضي |
| 401 | Client Error | Unauthorized | المستخدم غير معروف، ويجب عليه تسجيل الدخول أو إرسال Token صحيح، أي أن المشكلة متعلقة بالهوية |
| 403 | Client Error | Forbidden | المستخدم معروف لكن ليس لديه صلاحية للوصول للـ Resource، وهي مشكلة صلاحيات |
| 404 | Client Error | Not Found | الـ Resource المطلوب غير موجود على الـ Server |
| 405 | Client Error | Method Not Allowed | الـ HTTP Method المستخدم مثل DELETE غير مسموح به لهذا المسار |
| 409 | Client Error | Conflict | الطلب صحيح لكنه يتعارض مع حالة الـ Resource الحالية في قاعدة البيانات |
| 410 | Client Error | Gone | الـ Resource كان موجوداً ولكنه حُذف نهائياً ولن يعود |
| 415 | Client Error | Unsupported Media Type | نوع البيانات المرسلة غير مدعوم من قِبل الـ Server، مثل إرسال XML بدلاً من JSON |
| 422 | Client Error | Unprocessable Entity | البيانات سليمة في الصياغة لكنها غير صالحة أو لا تتوافق مع قواعد التحقق المعروفة بـ Validation أو شروط العمل |
| 429 | Client Error | Too Many Requests | تم تجاوز الحد الأقصى المسموح به من الطلبات في فترة زمنية قصيرة بسبب القيود المعروفة بـ Rate Limiting |
| 500 | Server Error | Internal Server Error | حدث خطأ داخلي غير متوقع في الـ Server |
| 501 | Server Error | Not Implemented | الميزة أو الخاصية المطلوبة غير مدعومة أو لم تُنفذ بعد |
| 502 | Server Error | Bad Gateway | الـ Server الوسيط مثل Gateway أو Reverse Proxy تلقى رداً غير صالح من الـ Server الأساسي |
| 503 | Server Error | Service Unavailable | الخدمة غير متاحة مؤقتاً مثل الصيانة، الضغط الزائد، أو إعادة التشغيل |
| 504 | Server Error | Gateway Timeout | الـ Server الوسيط مثل Gateway لم يتلق استجابة من الـ Server الأساسي في الوقت المحدد |