البرمجة

التعامل مع كائن الاستجابة في Express

التعامل مع كائن الإجابة (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.

javascript
app.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 فقط وتضمن تعيين رأس المحتوى المناسب.

javascript
app.get('/user', (req, res) => { res.json({ name: "أحمد", age: 30 }); });

3. إرسال ملفات باستخدام res.sendFile()

تتيح هذه الطريقة إرسال ملفات مباشرة للعميل مثل صور، ملفات PDF، أو أي نوع من الملفات.

javascript
app.get('/file', (req, res) => { res.sendFile('/path/to/file.pdf'); });

هنا يجب الانتباه إلى تحديد المسار الكامل أو استخدام دالة path.join() مع __dirname لضمان الدقة.

4. إعادة التوجيه باستخدام res.redirect()

تستخدم لإعادة توجيه العميل إلى عنوان URL آخر. يمكن إعادة التوجيه إلى مسار داخلي في التطبيق أو إلى موقع خارجي.

javascript
app.get('/old-route', (req, res) => { res.redirect('/new-route'); });

يمكن أيضاً تحديد كود الحالة:

javascript
res.redirect(301, '/new-route'); // إعادة توجيه دائم

5. تعيين رؤوس الاستجابة باستخدام res.set() أو res.header()

تُستخدم لضبط رؤوس HTTP في الرد، مثل تحديد نوع المحتوى، التحكم في الكاش، تهيئة CORS وغيرها.

javascript
res.set('Content-Type', 'text/plain'); res.send('نص بسيط');

6. تعيين رموز حالة الاستجابة باستخدام res.status()

يُمكن تحديد رمز الحالة HTTP (Status Code) بشكل يدوي، وهو أمر مهم للتعبير عن نتيجة الطلب (نجاح، فشل، خطأ، إعادة توجيه…).

javascript
res.status(404).send('الصفحة غير موجودة');

7. التعامل مع ملفات تعريف الارتباط (Cookies) عبر res.cookie()

يوفر Express طرق سهلة لإنشاء وتعديل ملفات تعريف الارتباط المرسلة إلى المتصفح.

javascript
res.cookie('token', 'abc123', { httpOnly: true, maxAge: 3600000 }); res.send('تم تعيين الكوكيز');

سير عمل كائن الاستجابة (res)

عند تلقي طلب HTTP، يتولى Express إنشاء كائن res المرتبط به. هذا الكائن يبقى حيًا طوال فترة معالجة الطلب حتى يتم إرسال الاستجابة. أي طريقة من طرق إرسال الردود مثل res.send() أو res.json() تقوم بإرسال الرد وتُغلق الاتصال عادة، لذلك لا يمكن استخدام res.send() أو ما شابهها أكثر من مرة في نفس الدالة.

مثلاً:

javascript
app.get('/', (req, res) => { res.send('الرد الأول'); res.send('الرد الثاني'); // هذا لن يعمل وسيؤدي إلى خطأ });

لذلك يجب التأكد من أن أي استدعاء لإرسال رد هو الأخير في معالجة الطلب.


التعامل مع التدفقات والردود الكبيرة

في بعض الحالات، يحتاج المطور إلى إرسال ردود كبيرة أو تدفقات بيانات مستمرة مثل ملفات الفيديو أو الصوت أو البيانات الكبيرة. في هذه الحالة يمكن استخدام كائن res مع خاصية التدفقات (Streams).

مثال لإرسال ملف باستخدام التدفق:

javascript
const 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():

javascript
app.get('/stream', (req, res) => { res.write('جزء 1 '); setTimeout(() => { res.write('جزء 2 '); res.end('نهاية البيانات'); }, 1000); });

ضبط رؤوس HTTP وإدارة التحكم في التخزين المؤقت

تحديد رؤوس HTTP بعناية يمكن أن يؤثر بشكل كبير على أداء التطبيق وسلوك المتصفح في التعامل مع الردود. من الرؤوس المهمة:

  • Content-Type: تحدد نوع البيانات المرسلة.

  • Cache-Control: تتحكم في كيفية تخزين المحتوى مؤقتًا في المتصفح أو الخوادم الوسيطة.

  • ETag و Last-Modified: تستخدم للتحكم في تحديث الموارد وتقليل حجم التنزيلات.

تحديد الرأس عبر:

javascript
res.set('Cache-Control', 'public, max-age=3600');

التعامل مع الأخطاء باستخدام res

يمكن تخصيص الردود لتتناسب مع حالات الأخطاء مثل 400 (طلب غير صالح)، 401 (غير مصرح)، 403 (ممنوع)، 404 (غير موجود)، 500 (خطأ داخلي في الخادم). عن طريق تعيين رموز الحالة المناسبة مع رسالة توضيحية:

javascript
app.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 عند إنشاء موارد جديدة.

مثال:

javascript
app.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 لتوفير استخدام الذاكرة.

  • إدارة الأخطاء عبر إعداد استجابات ملائمة يضمن وضوح التطبيق وسهولة تتبعه.


المصادر

  1. Official Express.js Documentation – Response

  2. Node.js HTTP Module – ServerResponse