في Express، يحمل req.params قيم المقاطع المسماة في مسار الطلب (/users/:id يعطي req.params.id)، ويحمل req.query سلسلة الاستعلام الواقعة بعد ? (/search?q=node يعطي req.query.q)، ويحمل req.body البيانات المرسلة في جسم الطلب. يُملأ req.params وreq.query في كل طلب، لكن req.body يبقى undefined حتى يقرأه محلل للجسم مثل app.use(express.json()). القيم في params وquery نصوص دائمًا.
يجيب الطلب الأول بـ {"params":{"userId":"7"},"query":{"sort":"new","limit":"2"}}. لاحظ علامات الاقتباس: 7 و2 نصان، فحوّلهما بـ Number() قبل إجراء عمليات حسابية أو المقارنة بأرقام. الآن غيّر الطريقة إلى POST، وأبقِ المسار /users/7/posts وأرسل الجسم {"title": "Hello", "draft": true}: الإجابة 201 مع "body":{"title":"Hello","draft":true}، حيث true قيمة منطقية حقيقية لأنها جاءت من JSON.
req.params مقابل req.query مقابل req.body
req.params | req.query | req.body | |
|---|---|---|---|
| مصدره | المسار، /users/:id | سلسلة الاستعلام، ?sort=new | جسم الطلب |
| مثال على العنوان أو الجسم | /users/7 | /users?sort=new | {"name": "Ada"} |
| القيمة | { id: '7' } | { sort: 'new' } | { name: 'Ada' } |
| الأنواع | نصوص | نصوص ومصفوفات نصوص | أيًا كان ما يحمله JSON |
| يحتاج إعدادًا | :name في المسار | لا شيء | app.use(express.json()) |
| الاستخدام المعتاد | أي مورد | التصفية والترتيب والصفحات | بيانات للإنشاء أو التحديث |
يمكن أن يحتوي المسار على عدة معاملات، ويصبح كل اسم مفتاحًا في req.params: يعطي /teams/:teamId/members/:memberId المعرّفين كليهما. والشرطة أو النقطة تفصل بينها أيضًا، فيحوّل /flights/:from-:to العنوان /flights/LAX-SFO إلى { from: 'LAX', to: 'SFO' }.
req.query مع المفاتيح المكررة والغائبة
المفتاح الذي يظهر مرتين يصبح مصفوفة، والمفتاح الغائب يكون undefined، فأعطِ الخيارات قيمًا افتراضية:
الإجابة هي {"page":1,"tags":["red","sale"],"raw":{"tag":["red","sale"]}}. أرسل GET /products?tag=red&page=3 فيبقى tags مصفوفة، ["red"]، لأن [].concat() يحوّل النص الواحد أو المصفوفة إلى مصفوفة. يحلل Express 5 سلاسل الاستعلام بالمحلل البسيط في Node، فيعطي ?filter[size]=m المفتاح "filter[size]" لا كائنًا متداخلًا؛ أما Express 4 فكان يجعله متداخلًا.
req.body يحتاج إلى express.json()
يسلّم Node الجسم كتدفق من البايتات. يقرؤه express.json() ويحلله ويضبط req.body، لكن فقط حين يحمل الطلب Content-Type: application/json. أما نماذج HTML فترسل application/x-www-form-urlencoded، التي تحتاج express.urlencoded() بدلًا منه.
أرسل POST /signup مع الجسم {"email": "ada@example.com"} فتحصل على 201 مع {"email":"ada@example.com","name":"anonymous"}. وأرسل جسمًا فارغًا فتحصل على 400. الجزء ?? {} مهم: من دونه، يرمي تفكيك undefined الخطأ TypeError مع أي طلب ليس فيه جسم JSON. وللتحقق الحقيقي من الشكل والأنواع، استخدم مكتبة مخططات مثل zod.
req.headers وreq.get()
req.headers كائن فيه كل ترويسات الطلب، بأسماء بأحرف صغيرة. وتقرأ req.get(name) ترويسة واحدة وتتجاهل حالة الأحرف، فتعيد req.get('Content-Type') وreq.get('content-type') القيمة نفسها. وهذه خصائص أخرى ستستخدمها:
قيمة path هي /whoami وقيمة originalUrl هي /whoami?debug=1. أضف الترويسة Authorization: Bearer abc في شريط الطلب وأرسله مرة أخرى: يصبح token هو "Bearer abc". داخل موجّه مركّب عبر app.use('/api', router)، يفقد req.path البادئة /api بينما يحتفظ بها req.originalUrl (تشرح صفحة التوجيه في Express التركيب).
أخطاء شائعة
قراءة req.body في طلب GET. لا ترسل المتصفحات ومعظم العملاء جسمًا مع GET. ضع خيارات GET في سلسلة الاستعلام.
فحص علامة في الاستعلام على أنها قيمة صحيحة. يعطي ?admin=false النص 'false'، وهو truthy، فيمر if (req.query.admin). قارن النصوص: req.query.admin === 'true'.
إرسال JSON دون الترويسة. العميل الذي يرسل JSON على أنه text/plain يحصل على req.body === undefined. اضبط Content-Type: application/json لدى العميل.
الأسئلة الشائعة
كيف أحصل على عنوان IP الخاص بالعميل في Express؟
اقرأ req.ip. خلف وكيل أو موازن أحمال يكون هذا عنوان الوكيل إلى أن تضبط app.set('trust proxy', 1)، فيقرأ Express الترويسة X-Forwarded-For بدلًا منه.
كيف أحصل على عنوان URL الكامل لطلب في Express؟
req.originalUrl هو المسار مع سلسلة الاستعلام كما أرسلها العميل. ابنِ العنوان المطلق بـ `${req.protocol}://${req.get('host')}${req.originalUrl}`.
كيف أتعامل مع رفع الملفات في Express؟
تصل الملفات المرفوعة بصيغة multipart/form-data، التي لا يحللها express.json() ولا express.urlencoded(). استخدم حزمة مثل multer، التي تضع الملفات في req.file أو req.files والحقول الأخرى في req.body.
كيف أقرأ cookie من الطلب؟
الترويسة الخام موجودة في req.get('cookie'). للحصول على كائن في req.cookies، ثبّت الحزمة cookie-parser وأضف app.use(cookieParser()).