Node.js: التوجيه والوسيط

آخر تحديث: 2026-08-26

كان مشروع واجهة برمجة التطبيقات (API) الخاص بـ«تشارلي» يضم في البداية خمس مسارات فقط، وجميعها مكتوبة بلغة app.js، وكان الكود لا يزال واضحًا إلى حد ما. وبعد شهرين، ارتفع عدد المسارات إلى 30، وتجاوز حجم الملف 500 سطر — وأصبح إجراء تغيير واحد على نقطة نهاية API يستغرق وقتًا طويلاً للغاية. قرر الفريق استخدام express.Router() لتقسيم المسارات إلى وحدات — حيث تم نقل مسارات المستخدمين إلى users.js، ومسارات المصادقة إلى auth.js، وتم نقل البرمجيات الوسيطة المخصصة للتسجيل إلى ملف منفصل. بعد التقسيم، أصبح لكل ملف مسؤولية واحدة، وتحسنت كفاءة الصيانة بشكل ملحوظ.

ستتعلم:


1. express.Router() Modular Routing

مع تزايد عدد المسارات، قد يؤدي وضع جميع المسارات في app.js إلى تضخم حجم الملفات ويجعل التعاون صعبًا. تتيح لك express.Router() إنشاء مثيلات مستقلة للمسارات ثم ربطها ببادئة مسار محددة في تطبيقك.

ميزة تحديد المسارات مباشرةً داخل التطبيق التوجيه المعياري عبر وحدة التوجيه (Router)
تنظيم الملفات كل شيء في ملف app.js تقسيمها إلى ملفات منفصلة حسب الوحدات النمطية
بادئة المسار حدد المسار الكامل لكل جذر تعيين بادئة موحدة عند التثبيت
التعاون بين أعضاء الفريق قيام عدة مستخدمين بتحرير الملف نفسه الصيانة المستقلة لكل وحدة
قابلية إعادة الاستخدام منخفضة عالية؛ يمكن إعادة استخدامها عبر المشاريع المختلفة

▶ مثال: إنشاء وحدة توجيه مستقلة للمستخدمين

JAVASCRIPT
// routes/users.js
const express = require('express');
const router = express.Router();

router.get('/', (req, res) => {
  res.json({ users: ['Alice', 'Bob'] });
});

router.get('/:id', (req, res) => {
  res.json({ user: req.params.id });
});

module.exports = router;
▶ جرّب الكود

▶ مثال: تضمين وحدة مسار في ملف app.js

JAVASCRIPT
// app.js
const express = require('express');
const app = express();
const userRouter = require('./routes/users');

app.use('/users', userRouter);

app.listen(3000, () => {
  console.log('Server running on port 3000');
});
▶ جرّب الكود

الزيارة إلى /users تتطابق مع router.get('/')، والزيارة إلى /users/42 تتطابق مع router.get('/:id').



2. معلمات المسار وسلاسل الاستعلام ونصوص الطلبات

يقدم Express ثلاث طرق لتلقي بيانات العملاء، كل منها مناسبة لسيناريوهات مختلفة.

مصدر البيانات كيفية الوصول مثال على عنوان URL الاستخدامات الشائعة
معلمات التوجيه req.params /users/42 تحدد موردًا معينًا
سلسلة الاستعلام req.query /users?role=admin التصفية، الفرز، البحث
نص الطلب req.body نص طلب POST إرسال بيانات النموذج/JSON

▶ مثال: معلمة المسار :id

JAVASCRIPT
app.get('/products/:id', (req, res) => {
  const productId = req.params.id;
  res.json({ productId });
});
▶ جرّب الكود

▶ مثال: استعلام سلسلة req.query

JAVASCRIPT
app.get('/products', (req, res) => {
  const { category, sort, page } = req.query;
  res.json({ category, sort, page: page || 1 });
});
▶ جرّب الكود

الوصول إلى /products?category=electronics&sort=price&page=2 وreq.query و{ category: 'electronics', sort: 'price', page: '2' }.

▶ مثال: نص الطلب req.body وexpress.json()

JAVASCRIPT
app.use(express.json());

app.post('/products', (req, res) => {
  const { name, price } = req.body;
  res.status(201).json({ name, price });
});
▶ جرّب الكود

ملاحظة: قيمتا req.query وreq.params هما سلسلتان نصيتان ويجب تحويلهما يدويًّا إلى أرقام.



3. أساسيات البرمجيات الوسيطة وآلية next()

تعد البرمجيات الوسيطة مفهومًا أساسيًّا في Express — فكل طلب يمر عبر سلسلة من البرمجيات الوسيطة، ويمكن لكل دالة من دوال البرمجيات الوسيطة قراءة الطلب، أو تعديل الاستجابة، أو تمرير التحكم إلى دالة البرمجيات الوسيطة التالية.

100%
graph LR
  A[Request] --> B[morgan Log]
  B --> C[express.json Analysis]
  C --> D[Custom auth Middleware]
  D --> E[Route Handling Functions]
  E --> F[Response]
  D -->|next error| G[Error-handling middleware]

▶ مثال: أبسط برنامج وسيط مخصص

JAVASCRIPT
function logger(req, res, next) {
  console.log(`${req.method} ${req.url} - ${new Date().toISOString()}`);
  next();
}

app.use(logger);
▶ جرّب الكود
القاعدة الوصف
يجب استدعاء next() وإلا، فسيتم تعليق الطلب، ولن يتلقى العميل أي رد على الإطلاق
ترتيب الاستدعاء هو ترتيب التنفيذ يتم تنفيذ البرامج الوسيطة المسجلة أولاً أولاً
app.use() ينطبق بشكل عام app.use('/api', ...) ينطبق فقط على المسار /api
next('route') تخطي برامج الوسيطة المتبقية للمسار الحالي


4. التكامل مع برامج الوسيطة التابعة لأطراف ثالثة

يوفر المجتمع مجموعة واسعة من برامج الوسيطة الجاهزة للاستخدام، والتي يمكن تفعيلها بسطر واحد من التعليمات البرمجية بعد التثبيت.

البرامج الوسيطة الغرض أمر التثبيت
cors حل مشكلات الطلبات عبر الأصول npm install cors
مورغان تسجيل طلبات HTTP npm install morgan
خوذة تجهيز خوذة للاستجابة في حالات الطوارئ npm install helmet
express-rate-limit حد معدل الطلبات npm install express-rate-limit
cookie-parser تحليل ملفات تعريف الارتباط npm install cookie-parser

▶ مثال: دمج CORS وMorgan وHelmet

JAVASCRIPT
const cors = require('cors');
const morgan = require('morgan');
const helmet = require('helmet');

app.use(helmet());
app.use(cors());
app.use(morgan('combined'));
app.use(express.json());
▶ جرّب الكود

ملاحظة: يُنصح بوضع البرامج الوسيطة المتعلقة بالأمان (Helmet) أولاً، تليها مباشرةً البرامج الوسيطة الخاصة بالتسجيل.



5. البرمجيات الوسيطة لمعالجة الأخطاء

اتفاقية Express: الدالة ذات المعلمات الأربعة (err, req, res, next) هي برمجية وسيطة لمعالجة الأخطاء. وعندما تستدعي أي برمجية وسيطة الدالة next(err)، فإنها تتخطى البرمجيات الوسيطة العادية التالية وتنتقل مباشرةً إلى البرمجية الوسيطة لمعالجة الأخطاء.

عنصر المقارنة البرمجيات الوسيطة القياسية البرمجيات الوسيطة لمعالجة الأخطاء
عدد المعلمات 3 (req، res، next) 4 (err، req، res، next)
طريقة التشغيل التنفيذ بالتتابع عند وصول الطلبات next(err) التشغيل
مكان التسجيل أي مكان يجب أن يوضع في النهاية
هل يمكن أن يكون هناك أكثر من واحد؟ نعم نعم، يتم تنفيذها بالترتيب

▶ مثال: برمجيات وسيطة عالمية لمعالجة الأخطاء

JAVASCRIPT
app.use((err, req, res, next) => {
  console.error(err.stack);
  res.status(err.status || 500).json({
    error: err.message || 'Internal Server Error'
  });
});
▶ جرّب الكود

▶ مثال: إحداث خطأ في المسار

JAVASCRIPT
app.get('/admin', (req, res, next) => {
  const err = new Error('Access denied');
  err.status = 403;
  next(err);
});
▶ جرّب الكود

6. Mermaid: الهيكل المعياري لتوجيه البيانات في جهاز التوجيه

100%
graph TD
  APP[app.js] --> UR["/users → userRouter"]
  APP --> AR["/auth → authRouter"]
  APP --> MW["middleware/logger.js"]
  UR --> U1["GET / → User List"]
  UR --> U2["GET /:id → User Details"]
  UR --> U3["POST / → Create a User"]
  AR --> A1["POST /login → Log In"]
  AR --> A2["POST /register → Register"]
  MW --> ML["Logging Middleware"]


7. مثال شامل: واجهة برمجة تطبيقات التوجيه المعيارية

في هذا المثال، يتم تقسيم برامج الوساطة الخاصة بتوجيه المستخدم وتوجيه المصادقة والتسجيل إلى ملفات منفصلة، ثم يتم دمجها في النهاية في app.js.

▶ مثال: middleware/logger.js — برنامج وسيط مخصص للتسجيل

JAVASCRIPT
الدالة logger(req, res, next) {
  const start = Date.now();
  res.on('finish', () => {
    const duration = Date.now() - start;
    console.log(`${req.method} ${req.originalUrl} ${res.statusCode} ${duration}ms`);
  });
  next();
}

module.exports = logger;
▶ جرّب الكود

▶ مثال: routes/users.js — وحدة مسارات المستخدمين

JAVASCRIPT
const express = require('express');
const router = express.Router();

let users = [
  { id: 1, name: 'Alice' },
  { id: 2, name: 'Bob' }
];

router.get('/', (req, res) => {
  res.json(users);
});

router.get('/:id', (req, res, next) => {
  const user = users.find(u => u.id === parseInt(req.params.id));
  if (!user) {
    const err = new Error('User not found');
    err.status = 404;
    return next(err);
  }
  res.json(user);
});

router.post('/', (req, res) => {
  const { name } = req.body;
  if (!name) {
    return res.status(400).json({ error: 'Name is required' });
  }
  const newUser = { id: users.length + 1, name };
  users.push(newUser);
  res.status(201).json(newUser);
});

module.exports = router;
▶ جرّب الكود

▶ مثال: routes/auth.js — وحدة مسارات المصادقة

JAVASCRIPT
const express = require('express');
const router = express.Router();

router.post('/login', (req, res) => {
  const { username, password } = req.body;
  if (!username || !password) {
    return res.status(400).json({ error: 'Username and password required' });
  }
  res.json({ message: 'Login successful', token: 'mock-jwt-token' });
});

router.post('/register', (req, res) => {
  const { username, email, password } = req.body;
  if (!username || !email || !password) {
    return res.status(400).json({ error: 'All fields are required' });
  }
  res.status(201).json({ message: 'Registration successful' });
});

module.exports = router;
▶ جرّب الكود

▶ مثال: app.js — نقطة دخول التكامل

JAVASCRIPT
const express = require('express');
const helmet = require('helmet');
const cors = require('cors');
const morgan = require('morgan');

const logger = require('./middleware/logger');
const userRouter = require('./routes/users');
const authRouter = require('./routes/auth');

const app = express();

app.use(helmet());
app.use(cors());
app.use(morgan('combined'));
app.use(express.json());
app.use(logger);

app.use('/users', userRouter);
app.use('/auth', authRouter);

app.use((req, res) => {
  res.status(404).json({ error: 'Route not found' });
});

app.use((err, req, res, next) => {
  console.error(err.stack);
  res.status(err.status || 500).json({
    error: err.message || 'Internal Server Error'
  });
});

app.listen(3000, () => {
  console.log('Server running on port 3000');
});
▶ جرّب الكود

تشغيل الاختبار:

BASH
node app.js
TEXT 📖 للعرض فقط
Server running on port 3000
GET /users 200 3ms
GET /users/1 200 2ms
POST /auth/login 200 5ms


❓ أسئلة شائعة

س ماذا يحدث إذا لم يتم استدعاء next()؟
ج سيتم تعليق الطلب، ولن يتلقى العميل أي استجابة على الإطلاق. يجب عليك استدعاء next() في البرمجيات الوسيطة لتمرير التحكم، أو استخدام طرق مثل res.end() أو res.json() لإنهاء الاستجابة مباشرةً.
س ما الفرق بين معلمات المسار ومعلمات الاستعلام؟
ج معلمات المسار هي جزء من مسار عنوان URL، مثل الرقم 42 في /users/:id، والتي يمكن استردادها باستخدام req.params.id؛ أما معلمات الاستعلام فهي أزواج من المفاتيح والقيم التي تلي علامة «؟»، مثل /users?role=admin، والتي يمكن استردادها باستخدام req.query.role. الأولى تحدد الموارد، بينما الثانية تقوم بتصفية الموارد.
س هل يهم ترتيب تسجيل برامج الوسيطة؟
ج إنه مهم جدًّا. يقوم Express بتنفيذ برامج الوسيطة بالترتيب الذي تم تسجيلها به. على سبيل المثال، يجب تسجيل express.json() قبل أي مسار يحتاج إلى قراءة req.body؛ وإلا فإن req.body سيصبح undefined.
س كيف يمكنني تنفيذ معالجة الأخطاء الشاملة؟
ج قم بتعريف دالة ذات 4 معلمات (err، req، res، next) وقم بتسجيلها باستخدام app.use() بعد جميع المسارات والبرمجيات الوسيطة. وسيتم توجيه أي برمجية وسيطة تستدعي next(err) إلى هذا المعالج.
س ما هي المشكلة التي تحلها البرمجيات الوسيطة CORS؟
ج تعمل سياسة «نفس المنشأ» (same-origin policy) في المتصفح على حظر الطلبات عبر المنشأ. وتقوم البرمجيات الوسيطة CORS بإضافة حقول مثل Access-Control-Allow-Origin إلى رؤوس الاستجابة، مما يسمح لتطبيقات الواجهة الأمامية من منشآت محددة بالوصول إلى واجهة برمجة التطبيقات (API).
س ما الفرق بين express.Router() واستخدام app.get() مباشرةً؟
ج يقوم Router بإنشاء مثيل موجه مستقل يمكن ربطه بأي بادئة مسار، مما يجعله مناسبًا للتقسيم إلى وحدات؛ أما app.get() فيتم تسجيله مباشرةً على مثيل التطبيق، مما يجعله مناسبًا للمشاريع البسيطة. كلاهما متكافئان من الناحية الوظيفية؛ ويكمن الاختلاف في طريقة تنظيمهما.
س كيف يمكنني تعديل الكائن req في برنامج وسيط لتمرير البيانات إلى المراحل التالية من المعالجة؟
ج ما عليك سوى ربط الخصائص مباشرةً بـ req، مثل req.user = { id: 1 }. وبذلك، يمكن لبرامج الوسيطة والمسارات التالية الوصول إلى هذه البيانات عبر req.user. وهذا نمط شائع للتواصل بين برامج الوسيطة في Express.

📖 ملخص


📝 تمارين

  1. أكمل جميع أمثلة الأكواد الواردة في هذا الدرس وتأكد من أن كل منها يعمل بشكل صحيح.
  2. قم بتعديل المثال الشامل وأضف الإضافات الخاصة بك
  3. راجع الوثائق الرسمية، وحدد واجهة برمجة تطبيقات (API) واحدة أو اثنتين لم يتم تناولهما في هذا الدرس، واكتب كود اختبار لهما.
  4. التأمل: كيف ستطبق ما تعلمته في هذا الدرس على مشروع في الواقع العملي؟
  5. حاول أن تجمع بين ما تعلمته في هذا الدرس والمواد التي درستها في الدروس السابقة لإنشاء مشروع صغير.
Web-Tutorial.com

فريق Web-Tutorial التقني

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

100%