التعامل مع كائن الإجابة (res) في إطار العمل Express
يُعتبر إطار العمل Express من أكثر أُطُر تطوير تطبيقات الويب شيوعاً في بيئة Node.js، حيث يُستخدم لبناء تطبيقات وخدمات الويب بسرعة وفعالية. من العناصر الأساسية التي يواجهها المطور عند التعامل مع Express هو كائن الاستجابة (response object)، الذي يُشار إليه عادةً بالاختصار res. في هذا المقال سنقوم بتناول كائن res بشكل موسع، نشرح طبيعة عمله، كيفية استخدامه في إرسال الردود إلى العميل، وظائفه المتعددة، وأهم الممارسات المتعلقة بالتعامل معه ضمن تطبيقات Express.
مفهوم كائن الاستجابة (res) في Express
عند استقبال طلب HTTP من العميل (المتصفح أو تطبيق آخر)، يقوم Express بتوفير كائنين رئيسيين لمُعالجة الطلب وهما: كائن الطلب req وكائن الاستجابة res. كائن req يحتوي على معلومات حول الطلب الذي أرسله العميل، مثل البيانات المرسلة، رؤوس الطلب، نوع الطلب، وغير ذلك. أما كائن res فهو المسؤول عن بناء الرد المناسب وإرساله للعميل.
بمعنى آخر، يمثل res الوسيلة التي من خلالها يوجه الخادم الاستجابة للعميل، سواء كانت استجابة نصية، HTML، JSON، ملفات، أو حتى رموز حالة HTTP.
الهيكلية العامة لكائن الاستجابة res
كائن res هو نسخة من كائن http.ServerResponse الأصلي الخاص بـ Node.js، مضافًا إليه ميزات Express لتسهيل العمل، مثل:
-
طرق إرسال الردود (مثل
res.send()وres.json()). -
طرق تعديل رؤوس الاستجابة (مثل
res.set()وres.header()). -
طرق إعادة التوجيه (مثل
res.redirect()). -
طرق التعامل مع ملفات الـ cookies (مثل
res.cookie()). -
وغيرها من الطرق التي توفر مرونة كبيرة في التعامل مع الردود.
الوظائف الأساسية لكائن res وكيفية استخدامها
1. إرسال الرد باستخدام res.send()
تُعد الطريقة res.send() من أبسط الطرق وأشهرها لإرسال رد من الخادم إلى العميل. يمكن من خلالها إرسال نصوص، كائنات JSON، مصفوفات، ملفات Buffer، وحتى HTML.
javascriptapp.get('/', (req, res) => {
res.send('مرحباً بك في موقعنا!');
});
في هذا المثال، يتم إرسال نص بسيط كرد على طلب GET إلى المسار الأساسي.
عند تمرير كائن JSON إلى res.send()، يقوم Express بتحويله تلقائياً إلى JSON مع تعيين رأس المحتوى Content-Type إلى application/json.
2. إرسال JSON باستخدام res.json()
تستخدم هذه الطريقة بشكل خاص لإرسال البيانات بصيغة JSON. الفرق بينها وبين res.send() هو أن res.json() مخصصة لإرسال JSON فقط وتضمن تعيين رأس المحتوى المناسب.
javascriptapp.get('/user', (req, res) => {
res.json({ name: "أحمد", age: 30 });
});
3. إرسال ملفات باستخدام res.sendFile()
تتيح هذه الطريقة إرسال ملفات مباشرة للعميل مثل صور، ملفات PDF، أو أي نوع من الملفات.
javascriptapp.get('/file', (req, res) => {
res.sendFile('/path/to/file.pdf');
});
هنا يجب الانتباه إلى تحديد المسار الكامل أو استخدام دالة path.join() مع __dirname لضمان الدقة.
4. إعادة التوجيه باستخدام res.redirect()
تستخدم لإعادة توجيه العميل إلى عنوان URL آخر. يمكن إعادة التوجيه إلى مسار داخلي في التطبيق أو إلى موقع خارجي.
javascriptapp.get('/old-route', (req, res) => {
res.redirect('/new-route');
});
يمكن أيضاً تحديد كود الحالة:
javascriptres.redirect(301, '/new-route'); // إعادة توجيه دائم
5. تعيين رؤوس الاستجابة باستخدام res.set() أو res.header()
تُستخدم لضبط رؤوس HTTP في الرد، مثل تحديد نوع المحتوى، التحكم في الكاش، تهيئة CORS وغيرها.
javascriptres.set('Content-Type', 'text/plain');
res.send('نص بسيط');
6. تعيين رموز حالة الاستجابة باستخدام res.status()
يُمكن تحديد رمز الحالة HTTP (Status Code) بشكل يدوي، وهو أمر مهم للتعبير عن نتيجة الطلب (نجاح، فشل، خطأ، إعادة توجيه…).
javascriptres.status(404).send('الصفحة غير موجودة');
7. التعامل مع ملفات تعريف الارتباط (Cookies) عبر res.cookie()
يوفر Express طرق سهلة لإنشاء وتعديل ملفات تعريف الارتباط المرسلة إلى المتصفح.
javascriptres.cookie('token', 'abc123', { httpOnly: true, maxAge: 3600000 });
res.send('تم تعيين الكوكيز');
سير عمل كائن الاستجابة (res)
عند تلقي طلب HTTP، يتولى Express إنشاء كائن res المرتبط به. هذا الكائن يبقى حيًا طوال فترة معالجة الطلب حتى يتم إرسال الاستجابة. أي طريقة من طرق إرسال الردود مثل res.send() أو res.json() تقوم بإرسال الرد وتُغلق الاتصال عادة، لذلك لا يمكن استخدام res.send() أو ما شابهها أكثر من مرة في نفس الدالة.
مثلاً:
javascriptapp.get('/', (req, res) => {
res.send('الرد الأول');
res.send('الرد الثاني'); // هذا لن يعمل وسيؤدي إلى خطأ
});
لذلك يجب التأكد من أن أي استدعاء لإرسال رد هو الأخير في معالجة الطلب.
التعامل مع التدفقات والردود الكبيرة
في بعض الحالات، يحتاج المطور إلى إرسال ردود كبيرة أو تدفقات بيانات مستمرة مثل ملفات الفيديو أو الصوت أو البيانات الكبيرة. في هذه الحالة يمكن استخدام كائن res مع خاصية التدفقات (Streams).
مثال لإرسال ملف باستخدام التدفق:
javascriptconst fs = require('fs');
app.get('/video', (req, res) => {
const stream = fs.createReadStream('video.mp4');
res.writeHead(200, { 'Content-Type': 'video/mp4' });
stream.pipe(res);
});
هذا يسمح بإرسال البيانات تدريجيًا دون تحميل الملف كاملاً في الذاكرة.
التحكم في الوقت المستغرق للإرسال وإنهاء الاتصال
يمكن من خلال res التحكم في وقت الاستجابة وإنهاء الاتصال يدوياً عبر:
-
res.end(): تُستخدم لإنهاء الاستجابة دون إرسال أي بيانات إضافية. -
res.send(): ترسل البيانات وتغلق الاستجابة تلقائياً. -
res.write(): تسمح بكتابة بيانات جزئية وتستمر في إبقاء الاتصال مفتوحاً.
مثال على استخدام res.write() و res.end():
javascriptapp.get('/stream', (req, res) => {
res.write('جزء 1 ');
setTimeout(() => {
res.write('جزء 2 ');
res.end('نهاية البيانات');
}, 1000);
});
ضبط رؤوس HTTP وإدارة التحكم في التخزين المؤقت
تحديد رؤوس HTTP بعناية يمكن أن يؤثر بشكل كبير على أداء التطبيق وسلوك المتصفح في التعامل مع الردود. من الرؤوس المهمة:
-
Content-Type: تحدد نوع البيانات المرسلة. -
Cache-Control: تتحكم في كيفية تخزين المحتوى مؤقتًا في المتصفح أو الخوادم الوسيطة. -
ETagوLast-Modified: تستخدم للتحكم في تحديث الموارد وتقليل حجم التنزيلات.
تحديد الرأس عبر:
javascriptres.set('Cache-Control', 'public, max-age=3600');
التعامل مع الأخطاء باستخدام res
يمكن تخصيص الردود لتتناسب مع حالات الأخطاء مثل 400 (طلب غير صالح)، 401 (غير مصرح)، 403 (ممنوع)، 404 (غير موجود)، 500 (خطأ داخلي في الخادم). عن طريق تعيين رموز الحالة المناسبة مع رسالة توضيحية:
javascriptapp.use((req, res) => {
res.status(404).send('لم يتم العثور على الصفحة المطلوبة');
});
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).send('حدث خطأ في الخادم');
});
التعامل مع استجابات RESTful API باستخدام res
في تطبيقات الـ API التي تعتمد على REST، يصبح من الضروري التزام بنقل معلومات دقيقة في الردود مثل:
-
إرسال بيانات JSON محدثة.
-
تعيين رموز حالة واضحة (200 للنجاح، 201 لإنشاء، 204 للحذف بدون محتوى، 400 للأخطاء العميلية، 500 للأخطاء الخادمية).
-
تضمين رؤوس خاصة مثل
Locationعند إنشاء موارد جديدة.
مثال:
javascriptapp.post('/users', (req, res) => {
const newUser = createUser(req.body);
res.status(201).location(`/users/${newUser.id}`).json(newUser);
});
جدول يوضح أهم دوال كائن res واستخداماتها
| الدالة | الوصف | المثال |
|---|---|---|
res.send() |
إرسال نص، JSON، Buffer، HTML | res.send('مرحبا') |
res.json() |
إرسال رد JSON | res.json({ name: 'علي' }) |
res.sendFile() |
إرسال ملف للعميل | res.sendFile('/path/file.pdf') |
res.redirect() |
إعادة توجيه العميل | res.redirect('/home') |
res.status() |
تعيين كود حالة HTTP | res.status(404).send('غير موجود') |
res.set() |
تعيين رأس استجابة HTTP | res.set('Content-Type', 'text/plain') |
res.cookie() |
تعيين كوكيز | res.cookie('token', 'xyz') |
res.write() |
كتابة جزء من البيانات بدون إنهاء الاتصال | res.write('جزء') |
res.end() |
إنهاء الاستجابة | res.end() |
ملخص وملاحظات هامة
-
كائن
resهو المفتاح الرئيسي لإرسال أي رد من الخادم إلى العميل في Express. -
استخدام الوظائف المتعددة لكائن
resيمنح المرونة الكاملة لبناء أنواع مختلفة من الردود (نص، JSON، ملفات، إعادة توجيه). -
يجب الانتباه إلى أن إرسال رد واحد فقط يتم لكل طلب، وأن محاولات إرسال رد متعدد تؤدي إلى أخطاء.
-
التحكم في الرؤوس والرموز يعزز من أداء التطبيق وتجربة المستخدم.
-
في حالة التعامل مع تدفقات البيانات الكبيرة، من الأفضل استخدام
streamمعresلتوفير استخدام الذاكرة. -
إدارة الأخطاء عبر إعداد استجابات ملائمة يضمن وضوح التطبيق وسهولة تتبعه.

