اذهب إلى المحتوى

سنتعرّف من خلال هذا المقال على وحدات Node.js الأساسية مثل وحدة fs وpath وos وevents وتوابعها المتعددة، كما يمكنك بناء وحدة مخصَّصة بالاعتماد على الوحدات الأساسية، حيث سنتعرّف على كيفية استخدام واجهة module.exports البرمجية لتصدير بياناتك، وسنتعرّف على وحدة MySQL للتعامل مع قواعد البيانات.

وحدة fs

توفّر وحدة fs عمليات متعددة ومفيدة للوصول إلى نظام الملفات والتفاعل معه، وليست هناك حاجة لتثبيتها نظرًا لكونها جزءًا من نواة نود، إذ يمكن استخدامها ببساطة عن طريق طلبها كما يلي:

const fs = require('fs')

ثم يمكنك الوصول إلى جميع توابعها التي تشمل ما يلي:

  • fs.access()‎: يتحقق من وجود الملف ويمكن لنود الوصول إلى الملف باستخدام أذوناته.
  • fs.appendFile()‎: يُلحِق بيانات بملف، وينشئ الملف إذا كان غير موجود مسبقًا.
  • fs.chmod()‎: يغيّر أذونات الملف المحدَّد بواسطة اسم الملف المُمرَّر، ويتعلق بالتابعَين fs.lchmod()‎ وfs.fchmod()‎.
  • fs.chown()‎: يغيّر مالك ومجموعة الملف المحدَّد بواسطة اسم الملف المُمرَّر، ويتعلق بالتابعَين fs.fchown()‎ وfs.lchown()‎.
  • fs.close()‎: يغلق واصف الملف file descriptor.
  • fs.copyFile()‎: ينسخ ملفًا.
  • fs.createReadStream()‎: ينشئ مجرى stream ملف قابل للقراءة.
  • fs.createWriteStream()‎: ينشئ مجرى ملف قابل للكتابة.
  • fs.link()‎: ينشئ رابطًا صلبًا hard link جديدًا إلى ملف.
  • fs.mkdir()‎: ينشئ مجلدًا جديدًا.
  • fs.mkdtemp()‎: ينشئ مجلدًا مؤقتًا.
  • fs.open()‎: يضبط نمط الملف.
  • fs.readdir()‎: يقرأ محتويات مجلد.
  • fs.readFile()‎: يقرأ محتوى ملف، ويتعلق بالتابع fs.read()‎.
  • fs.readlink()‎: يقرأ قيمة الوصلة الرمزية symbolic link.
  • fs.realpath()‎: يُستخدَم لربط resolve مؤشرات مسار الملف النسبي (. و..) مع المسار الكامل.
  • fs.rename()‎: يعيد تسمية ملف أو مجلد.
  • fs.rmdir()‎: يزيل مجلدًا.
  • fs.stat()‎: يعيد حالة الملف المحدَّد بواسطة اسم الملف المُمرَّر، ويتعلق بالتابعَين fs.fstat()‎ وfs.lstat()‎.
  • fs.symlink()‎: ينشئ وصلةً رمزيةً جديدًا إلى ملف.
  • fs.truncate()‎: يقتطع الملف المحدَّد بواسطة اسم الملف المُمرَّر إلى طول معيَّن، ويتعلق بالتابع fs.ftruncate()‎.
  • fs.unlink()‎: يزيل ملفًا أو وصلةً رمزيةً.
  • fs.unwatchFile()‎: يوقِف مشاهدة التغييرات على ملف.
  • fs.utimes()‎: يغيّر الطابع الزمني timestamp للملف المحدَّد باسم الملف المُمرَّر، ويتعلق بالتابع fs.futimes()‎.
  • fs.watchFile()‎: يبدأ بمشاهدة التغييرات على ملف، ويتعلق بالتابع fs.watch()‎.
  • fs.writeFile()‎: يكتب بيانات في ملف، ويتعلق بالتابع: fs.write()‎.

جميع التوابع في وحدة fs غير متزامنة افتراضيًا، ولكن يمكنها العمل بطريقة متزامنة من خلال إلحاق الكلمة Sync باسم التابع كما يلي:

  • fs.rename()‎
  • fs.renameSync()‎
  • fs.write()‎
  • fs.writeSync()‎

ويحدِث ذلك فرقًا كبيرًا في تدفق تطبيقك.

اقتباس

توضيح: تتضمن نود 10 أنواع من الدعم التجريبي لواجهة برمجة تطبيقات قائمة على الوعود promise.

لنختبر التابع fs.rename()‎ مثلًا، حيث تُستخدَم واجهة برمجة التطبيقات API غير المتزامنة مع دالة رد نداء callback:

const fs = require('fs')

fs.rename('before.json', 'after.json', (err) => {
  if (err) {
    return console.error(err)
  }
  //done
})

يمكن استخدام واجهة برمجة تطبيقات متزامنة مثل المثال التالي مع كتلة try/catch لمعالجة الأخطاء:

const fs = require('fs')

try {
  fs.renameSync('before.json', 'after.json')
  //done
} catch (err) {
  console.error(err)
}

الاختلاف الرئيسي هو إيقاف تنفيذ السكربت الخاص بك في المثال الثاني إلى أن تنجح عملية الملف.

للمزيد من المعلومات حول هذه الوحدة، يمكنك الرجوع إلى توثيق التعامل مع نظام الملفات في Node.js في موسوعة حسوب.

وحدة المسار path

توفِّر وحدة path عمليات متعددة ومفيدة للوصول إلى نظام الملفات والتفاعل معه، وليست هناك حاجة لتثبيتها نظرًا لكونها جزءًا من نواة نود، إذ يمكن استخدامها ببساطة عن طريق طلبها كما يلي:

const path = require('path')

توفِّر هذه الوحدة محرف path.sep الذي يوفّر فاصل مقاطع المسار path segment separator (\ على نظام ويندوز Windows و/ على نظامي لينكس Linux وmacOS)، بالإضافة إلى محرف path.delimiter الذي يوفّر محدّد المسار path delimiter (; على ويندوز Windows و: على نظامَي لينكس Linux وmacOS).

توابع وحدة path هي:

  • path.basename()‎
  • path.dirname()‎
  • path.extname()‎
  • path.isAbsolute()‎
  • path.join()‎
  • path.normalize()‎
  • path.parse()‎
  • path.relative()‎
  • path.resolve()‎

للمزيد من المعلومات حول هذه الوحدة، يمكنك الرجوع إلى توثيق وحدة المسار (Path) في Node.js في موسوعة حسوب.

التابع path.basename()‎

يعيد هذا التابع الجزء الأخير من المسار، ويمكن للمعامِل الثاني تحديد امتداد الملف لإعطاء الملف دون امتداده كما يلي:

require('path').basename('/test/something') //something
require('path').basename('/test/something.txt') //something.txt
require('path').basename('/test/something.txt', '.txt') //something

التابع path.dirname()‎

يعيد هذا التابع جزء المجلد أو الدليل من المسار كما يلي:

require('path').dirname('/test/something') // /test
require('path').dirname('/test/something/file.txt') // /test/something

التابع path.extname()‎

يعيد هذا التابع جزء الامتداد من المسار كما يلي:

require('path').dirname('/test/something') // ''
require('path').dirname('/test/something/file.txt') // '.txt'

التابع path.isAbsolute()‎

يعيد هذا التابع القيمة true إذا كان المسار مسارًا مطلقًا.

require('path').isAbsolute('/test/something') // true
require('path').isAbsolute('./test/something') // false

التابع path.join()‎

يربط هذا التابع جزأين أو أكثر من المسار مع بعضها البعض كما يلي:

const name = 'flavio'
require('path').join('/', 'users', name, 'notes.txt') //'/users/flavio/notes.txt'

التابع path.normalize()‎

يحاول هذا التابع حساب المسار الفعلي عندما يحتوي على محددات نسبية مثل . أو .. أو شرطات مائلة مزدوجة:

require('path').normalize('/users/flavio/..//test.txt') ///users/test.txt

التابع path.parse()‎

يوزّع هذا التابع مسارًا على كائن يتكون من أجزاء متعددة هي:

  • root: يمثّل الجذر.
  • dir: هو مسار المجلد بداية من الجذر.
  • base: يمثّل اسم الملف مع الامتداد.
  • name: هو اسم الملف.
  • ext: يمثّل امتداد الملف.

إليك المثال التالي:

require('path').parse('/users/test.txt')

وتكون النتيجة كما يلي:

{
  root: '/',
  dir: '/users',
  base: 'test.txt',
  ext: '.txt',
  name: 'test'
}

التابع path.relative()‎

يقبل هذا التابع مسارين على أساس وسائط، ويعيد المسار النسبي من المسار الأول إلى المسار الثاني بناءً على مجلد العمل الحالي مثل المثال التالي:

require('path').relative('/Users/flavio', '/Users/flavio/test.txt') //'test.txt'
require('path').relative('/Users/flavio', '/Users/flavio/something/test.txt') //'something/test.txt'

التابع path.resolve()‎

يمكنك حساب المسار المطلق لمسار نسبي باستخدام التابع path.resolve()‎ كما يلي:

path.resolve('flavio.txt') //‫'‎/Users/flavio/flavio.txt' إذا شُغِّل من المجلد المحلي

إذا حدّدت المعامل الثاني، فسيستخدم التابع resolve المعامِل الأول أساسًا للمعامِل الثاني كما يلي:

path.resolve('tmp', 'flavio.txt') // '/Users/flavio/tmp/flavio.txt' إذا شُغِّل من المجلد المحلي

إذا بدأ المعامِل الأول بشرطة مائلة، فهذا يعني أنه مسار مطلق كما يلي:

path.resolve('/etc', 'flavio.txt')//'/etc/flavio.txt'

وحدة os

توفِّر هذه الوحدة عمليات متعددة يمكنك استخدامها لاسترداد معلومات من نظام التشغيل الأساسي والحاسوب الذي يعمل عليه البرنامج والتفاعل معه.

const os = require('os')

هناك بعض الخاصيات المفيدة التي تخبرنا ببعض الأمور الأساسية المتعلقة بمعالجة الملفات مثل:

  • os.EOL التي تعطينا متسلسلة محدّد السطور، وهي ‎\n على نظامَي لينكس Linux وmacOS؛ أما على نظام ويندوز Windows فهي ‎\r\n.
اقتباس

توضيح: نقصد بنظامَي لينكس وmacOS منصات POSIX، واستبعدنا بهدف التبسيط أنظمة التشغيل الأخرى الأقل شيوعًا التي يمكن تشغيل نود Node عليها.

  • os.constants.signals التي تعطينا كل الثوابت المتعلقة بمعالجة إشارات العمليات مثل SIGHUP وSIGKILL وما إلى ذلك، كما يمكنك الاطلاع على جميع هذه الثوابت على /node_os.
  • os.constants.errno التي تضبط الثوابت في تقارير الخطأ مثل EADDRINUSE وEOVERFLOW وغير ذلك.

لنتعرّف الآن على التوابع الرئيسية التي توفرها وحدة os وهي:

  • os.arch()‎
  • os.cpus()‎
  • os.endianness()‎
  • os.freemem()‎
  • os.homedir()‎
  • os.hostname()‎
  • os.hostname()‎
  • os.loadavg()‎
  • os.networkInterfaces()‎
  • os.platform()‎
  • os.release()‎
  • os.tmpdir()‎
  • os.totalmem()‎
  • os.type()‎
  • os.uptime()‎
  • os.userInfo()‎

للمزيد من المعلومات حول هذه الوحدة، يمكنك الرجوع إلى توثيق الوحدة os في Node.js في موسوعة حسوب.

التابع os.arch()‎

يعيد هذا التابع السلسلة النصية التي تحدد البنية الأساسية مثل arm وx64 وarm64.

التابع os.cpus()‎

يعيد معلومات وحدات المعالجة المركزية المتوفرة على نظامك، وإليك المثال التالي:

[ { model: 'Intel(R) Core(TM)2 Duo CPU P8600 @ 2.40GHz',
   speed: 2400,
   times:
   { user: 281685380,
     nice: 0,
     sys: 187986530,
     idle: 685833750,
     irq: 0 } },
 { model: 'Intel(R) Core(TM)2 Duo CPU P8600 @ 2.40GHz',
   speed: 2400,
   times:
   { user: 282348700,
     nice: 0,
     sys: 161800480,
     idle: 703509470,
     irq: 0 } } ]

التابع os.endianness()‎

يعيد هذا التابع القيمة BE أو القيمة LE بناءً على طريقة تصريف نود باستخدام تخزين البتات الأقل أهمية أولًا Big Endian أو تخزين البتات الأكثر أهمية أولًا Little Endian.

التابع os.freemem()‎

يعيد هذا التابع عدد البايتات التي تمثل الذاكرة المتاحة في النظام.

التابع os.homedir()‎

يعيد هذا التابع المسار إلى مجلد المستخدِم الحالي الرئيسي مثل المثال التالي:

'/Users/flavio'

التابع os.hostname()‎

يعيد هذا التابع اسم المضيف hostname.

التابع os.loadavg()‎

يعيد هذا التابع الحساب الذي أجراه نظام التشغيل على متوسط التحميل، حيث يعيد فقط قيمة ذات معنى في نظامَي لينكس Linux وmacOS مثل المثال التالي:

[ 3.68798828125, 4.00244140625, 11.1181640625 ]

التابع os.networkInterfaces()‎

يعيد هذا التابع تفاصيل واجهات الشبكة المتوفرة على نظامك، وإليك المثال التالي:

{ lo0:
 [ { address: '127.0.0.1',
     netmask: '255.0.0.0',
     family: 'IPv4',
     mac: 'fe:82:00:00:00:00',
     internal: true },
   { address: '::1',
     netmask: 'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff',
     family: 'IPv6',
     mac: 'fe:82:00:00:00:00',
     scopeid: 0,
     internal: true },
   { address: 'fe80::1',
     netmask: 'ffff:ffff:ffff:ffff::',
     family: 'IPv6',
     mac: 'fe:82:00:00:00:00',
     scopeid: 1,
     internal: true } ],
 en1:
 [ { address: 'fe82::9b:8282:d7e6:496e',
     netmask: 'ffff:ffff:ffff:ffff::',
     family: 'IPv6',
     mac: '06:00:00:02:0e:00',
     scopeid: 5,
     internal: false },
 { address: '192.168.1.38',
     netmask: '255.255.255.0',
     family: 'IPv4',
     mac: '06:00:00:02:0e:00',
     internal: false } ],
 utun0:
 [ { address: 'fe80::2513:72bc:f405:61d0',
     netmask: 'ffff:ffff:ffff:ffff::',
     family: 'IPv6',
     mac: 'fe:80:00:20:00:00',
     scopeid: 8,
     internal: false } ] }

التابع os.platform()‎

يعيد هذا التابع المنصة الذي جرى تصريف نود من أجلها مثل:

  • darwin0.
  • freebsd.
  • linux.
  • openbsd.
  • win32.
  • وغيرها الكثير.

التابع os.release()‎

يعيد هذا التابع سلسلةً نصيةً تحدِّد رقم إصدار نظام التشغيل.

التابع os.tmpdir()‎

يعيد هذا التابع المسار إلى المجلد المؤقت المعيَّن.

التابع os.totalmem()‎

يعيد هذا التابع عدد البايتات الذي يمثِّل إجمالي الذاكرة المتوفرة في النظام.

التابع os.type()‎

يحدّد هذا التابع نظام التشغيل كما يلي:

  • Linux.
  • Darwin على نظام macOS.
  • Windows_NT على نظام ويندوز.

التابع os.uptime()‎

يعيد هذا التابع عدد الثواني التي عمل فيها الحاسوب منذ آخر إعادة تشغيل.

التابع os.userInfo()‎

يعيد معلومات عن المستخدِم الفعّال حاليًا.

وحدة الأحداث events

توفِّر لنا وحدة الأحداث events الصنف EventEmitter، وتُعَدّ أساسًا للعمل مع الأحداث في نود.

const EventEmitter = require('events')
const door = new EventEmitter()

يختبر مستمع الأحداث event listener أحداثه الخاصة ويستخدِم الحدثين التاليين:

  • newListener عند إضافة المستمع.
  • removeListener عند إزالة المستمع.

سنشرح فيما يلي التوابع المفيدة التالية:

  • emitter.addListener()‎
  • emitter.emit()‎
  • emitter.eventNames()‎
  • emitter.getMaxListeners()‎
  • emitter.listenerCount()‎
  • emitter.listeners()‎
  • emitter.off()‎
  • emitter.on()‎
  • emitter.once()‎
  • emitter.prependListener()‎
  • emitter.prependOnceListener()‎
  • emitter.removeAllListeners()‎
  • emitter.removeListener()‎
  • emitter.setMaxListeners()‎

للمزيد من المعلومات حول هذه الوحدة، يمكنك الرجوع إلى توثيق الأحداث في Node.js في موسوعة حسوب.

التابع emitter.addListener()‎

وهو الاسم البديل للتابع emitter.on()‎.

التابع emitter.emit()‎

يصدر هذا التابع حدثًا، حيث يستدعي بصورة متزامنة كل مستمع حدث بالترتيب الذي سُجِّلت به.

التابع emitter.eventNames()‎

يعيد هذا التابع مصفوفةً من السلاسل النصية التي تمثِّل الأحداث المُسجَّلة في كائن EventListener الحالي:

door.eventNames()

التابع emitter.getMaxListeners()‎

يُستخدَم هذا التابع للحصول على الحد الأقصى من المستمعين الذي يمكن إضافته إلى كائن EventListener، حيث يُضبَط هذا العدد افتراضيًا على القيمة 10 ولكن يمكن زيادته أو إنقاصه باستخدام setMaxListeners()‎.

door.getMaxListeners()

التابع emitter.listenerCount()‎

يُستخدَم هذا التابع للحصول على عدد مستمعي الحدث المُمرَّرين على أساس معامِلات كما يلي:

door.listenerCount('open')

التابع emitter.listeners()‎

يُستخدَم هذا التابع للحصول على مصفوفة مستمعي الحدث المُمرَّرين على أساس معامِلات كما يلي:

door.listeners('open')

التابع emitter.off()‎

يمثّل هذا التابع الاسم البديل للتابع emitter.removeListener()‎ المُضاف في الإصدار 10 من نود.

التابع emitter.on()‎

يضيف هذا التابع دالة رد النداء التي تُستدعَى عند إصدار حدث، ويُستخدَم هذا التابع كما يلي:

door.on('open', () => {
  console.log('Door was opened')
})

التابع emitter.once()‎

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

const EventEmitter = require('events')
const ee = new EventEmitter()

ee.once('my-event', () => {
  //ًاستدعِ دالة رد النداء مرةً واحدة
})

التابع emitter.prependListener()‎

يُضاف المستمع الذي تضيفه باستخدام on أو addListener في آخر طابور المستمعين ويُستدعَى أخيرًا كذلك، ولكنه يُضاف ويُستدعَى قبل المستمعين الآخرين باستخدام prependListener.

التابع emitter.prependOnceListener()‎

يُضاف المستمع الذي تضيفه باستخدام once في آخر طابور المستمعين ويُستدعَى أخيرًا كذلك، ولكنه يُضاف ويُستدعَى قبل المستمعين الآخرين باستخدام prependOnceListener.

التابع emitter.removeAllListeners()‎

يزيل هذا التابع جميع مستمعي الكائن الذي يصدر الأحداث ويستمع إلى حدث محدَّد:

door.removeAllListeners('open')

التابع emitter.removeListener()‎

يزيل مستمعًا محدَّدًا عن طريق حفظ دالة رد النداء في متغير عند إضافته، بحيث يمكنك الإشارة إليه لاحقًا:

const doSomething = () => {}
door.on('open', doSomething)
door.removeListener('open', doSomething)

التابع emitter.setMaxListeners()‎

يضبط الحد الأقصى لعدد المستمعين الذي يمكن إضافته إلى كائن EventListener، حيث يُضبَط هذا العدد افتراضيًا على القيمة 10 ولكن يمكن زيادته أو إنقاصه.

door.setMaxListeners(50)

وحدة HTTP

توفّر وحدة http في Node.js دوالًا وأصنافًا مفيدة لبناء خادم HTTP، وتُعَدّ الوحدة الأساسية لشبكات نود، كما يمكن تضمين وحدة http كما يلي:

const http = require('http')

توفّر وحدة http بعض الخاصيات properties والتوابع methods والأصناف classes.

للمزيد من المعلومات حول هذه الوحدة، يمكنك الرجوع إلى توثيق الوحدة HTTP في Node.js في موسوعة حسوب.

الخاصيات

توفِّر وحدة HTTP الخاصيات التالية:

  • http.METHODS
  • http.STATUS_CODES
  • http.globalAgent

الخاصية http.METHODS

تعطي هذه الخاصية قائمةً بجميع توابع HTTP المدعومة كما يلي:

> require('http').METHODS

 [ 'ACL',
   'BIND',
   'CHECKOUT',
   'CONNECT',
   'COPY',
   'DELETE',
   'GET',
   'HEAD',
   'LINK',
   'LOCK',
   'M-SEARCH',
   'MERGE',
   'MKACTIVITY',
   'MKCALENDAR',
   'MKCOL',
   'MOVE',
   'NOTIFY',
   'OPTIONS',
   'PATCH',
   'POST',
   'PROPFIND',
   'PROPPATCH',
   'PURGE',
   'PUT',
   'REBIND',
   'REPORT',
   'SEARCH',
   'SUBSCRIBE',
   'TRACE',
   'UNBIND',
   'UNLINK',
   'UNLOCK',
   'UNSUBSCRIBE' ]

الخاصية http.STATUS_CODES

تعطي هذه الخاصية قائمةً بجميع رموز حالة HTTP ووصفها كما يلي:

> require('http').STATUS_CODES

 { '100': 'Continue',
   '101': 'Switching Protocols',
   '102': 'Processing',
   '200': 'OK',
   '201': 'Created',
   '202': 'Accepted',
   '203': 'Non-Authoritative Information',
   '204': 'No Content',
   '205': 'Reset Content',
   '206': 'Partial Content',
   '207': 'Multi-Status',
   '208': 'Already Reported',
   '226': 'IM Used',
   '300': 'Multiple Choices',
   '301': 'Moved Permanently',
   '302': 'Found',
   '303': 'See Other',
   '304': 'Not Modified',
   '305': 'Use Proxy',
   '307': 'Temporary Redirect',
   '308': 'Permanent Redirect',
   '400': 'Bad Request',
   '401': 'Unauthorized',
   '402': 'Payment Required',
   '403': 'Forbidden',
   '404': 'Not Found',
   '405': 'Method Not Allowed',
   '406': 'Not Acceptable',
   '407': 'Proxy Authentication Required',
   '408': 'Request Timeout',
   '409': 'Conflict',
   '410': 'Gone',
   '411': 'Length Required',
   '412': 'Precondition Failed',
   '413': 'Payload Too Large',
   '414': 'URI Too Long',
   '415': 'Unsupported Media Type',
   '416': 'Range Not Satisfiable',
   '417': 'Expectation Failed',
   '418': 'I\'m a teapot',
   '421': 'Misdirected Request',
   '422': 'Unprocessable Entity',
   '423': 'Locked',
   '424': 'Failed Dependency',
   '425': 'Unordered Collection',
   '426': 'Upgrade Required',
   '428': 'Precondition Required',
   '429': 'Too Many Requests',
   '431': 'Request Header Fields Too Large',
   '451': 'Unavailable For Legal Reasons',
   '500': 'Internal Server Error',
   '501': 'Not Implemented',
   '502': 'Bad Gateway',
   '503': 'Service Unavailable',
   '504': 'Gateway Timeout',
   '505': 'HTTP Version Not Supported',
   '506': 'Variant Also Negotiates',
   '507': 'Insufficient Storage',
   '508': 'Loop Detected',
   '509': 'Bandwidth Limit Exceeded',
   '510': 'Not Extended',
   '511': 'Network Authentication Required' }

الخاصية http.globalAgent

تؤشّر هذه الخاصية إلى نسخة كائن الوكيل Agent العامة، والذي هو نسخة من الصنف http.Agent، حيث يُستخدَم هذا الصنف لإدارة الاتصالات المستمرة وإعادة استخدام عملاء HTTP، وهو المكوّن الأساسي من شبكات HTTP الخاصة بنود Node.

التوابع

توفِّر وحدة HTTP التوابع التالية:

  • http.createServer()‎
  • http.request()‎
  • http.get()‎

التابع http.createServer()‎

يعيد هذا التابع نسخةً جديدةً من الصنف http.Server، حيث يُستخدَم كما يلي:

const server = http.createServer((req, res) => {
  //معالجة كل طلب باستخدام دالة رد النداء هذه
})

التابع http.request()‎

ينشئ طلب HTTP إلى خادم، مما يؤدي إلى إنشاء نسخة من الصنف http.ClientRequest.

التابع http.get()‎

يشبه التابع http.request()‎، ولكنه يضبط تلقائيًا تابع HTTP على GET ويستدعي التابع req.end()‎ تلقائيًا.

الأصناف Classes

توفِّر وحدة HTTP خمسة أصناف هي:

  • http.Agent
  • http.ClientRequest
  • http.Server
  • http.ServerResponse
  • http.IncomingMessage

الصنف http.Agent

نُنشئ نود نسخةً عامةً من الصنف http.Agent لإدارة الاتصالات المستمرة وإعادة استخدام عملاء HTTP، وهو المكوّن الأساسي من شبكات HTTP الخاصة بنود Node، كما يتأكّد هذا الكائن من وضع كل طلب إلى الخادم في طابور ومن إعادة استخدام المقبس socket، كما أنه يحتفظ بمجمّع من المقابس بهدف تحسين الأداء.

الصنف http.ClientRequest

يُنشَأ الكائن http.ClientRequest عند استدعاء التابع http.request()‎ أو التابع http.get()‎، حيث يُستدعَى حدث response مع الاستجابة عند تلقيها باستخدام نسخة من كائن http.IncomingMessage على أساس وسيط، ويمكن قراءة بيانات الاستجابة المُعادة بطريقتين هما:

  • استدعاء التابع response.read()‎.
  • يمكنك إعداد مستمعٍ للحدث data في معالج الحدث response بحيث يمكنك الاستماع للبيانات المتدفقة إليه.

الصنف http.Server

تُنشَأ وتُعاد عادةً نسخة من هذا الصنف عند إنشاء خادم جديد باستخدام التابع http.createServer()‎، يمكنك الوصول إلى توابع كائن خادم بعد إنشائه، وهذه التوابع هي:

  • close()‎ الذي يوقِف الخادم من قبول اتصالات جديدة.
  • listen()‎ الذي يشغّل خادم HTTP ويستمع للاتصالات.

الصنف http.ServerResponse

ينشئه الصنف http.Server ويمرّره على أساس معامل ثانٍ لحدث request الذي يشغّله، حيث يُعرَف هذا الصنف ويُستخدَم في الشيفرة على أنه كائن res كما يلي:

const server = http.createServer((req, res) => {
  //‫res هو كائن http.ServerResponse
})

التابع الذي ستستدعيه دائمًا في المعالج هو end()‎ والذي يغلق الاستجابة بعد اكتمال الرسالة ثم يستطيع الخادم إرسالها إلى العميل، إذ يجب استدعاؤه في كل استجابة، وتُستخدَم التوابع التالية للتفاعل مع ترويسات HTTP:

  • getHeaderNames()‎: للحصول على قائمة بأسماء ترويسات HTTP المضبوطة مسبقًا.
  • getHeaders()‎: للحصول على نسخة من ترويسات HTTP المضبوطة مسبقًا.
  • setHeader('headername', value)‎: يحدّد قيمة ترويسة HTTP.
  • getHeader('headername')‎: للحصول على ترويسة HTTP المضبوطة مسبقًا.
  • removeHeader('headername')‎: يزيل ترويسة HTTP المضبوطة مسبقًا.
  • hasHeader('headername')‎: يعيد القيمة true إذا احتوت الاستجابة على هذه الترويسة المضبوطة.
  • headersSent()‎: يعيد القيمة true إذا أُرسِلت الترويسات إلى العميل. مسبقًا

يمكنك إرسال الترويسات بعد معالجتها إلى العميل عن طريق استدعاء التابع response.writeHead()‎ الذي يقبل رمز الحالة statusCode على أساس معامل أول، ورسالة الحالة الاختيارية، وكائن الترويسات، كما يمكنك إرسال البيانات إلى العميل في جسم الاستجابة عن طريق استخدام التابع write()‎ الذي سيرسل البيانات المخزَّنة إلى مجرى استجابة HTTP، فإذا لم تُرسَل الترويسات بعد باستخدام التابع response.writeHead()‎، فستُرسَل الترويسات أولًا مع رمز الحالة والرسالة المحدَّدة في الطلب والتي يمكنك تعديلها عن طريق ضبط قيم الخاصيات statusCode وstatusMessage كما يلي:

response.statusCode = 500
response.statusMessage = 'Internal Server Error'

الصنف http.IncomingMessage

يُنشَأ كائن http.IncomingMessage باستخدام:

  • http.Server عند الاستماع إلى الحدث request.
  • http.ClientRequest عند الاستماع إلى الحدث response.

يمكن استخدام كائن http.IncomingMessage للوصول إلى خاصيات الاستجابة التالية:

  • الحالة status باستخدام توابع statusCode وstatusMessage الخاصة به.
  • الترويسات باستخدام توابع headers أو rawHeaders الخاصة به.
  • تابع HTTP باستخدام تابع method الخاص به.
  • إصدار HTTP باستخدام تابع httpVersion.
  • عنوان URL باستخدام تابع url.
  • المقبس الأساسي underlying socket باستخدام تابع socket.

يمكن الوصول إلى البيانات باستخدام المجاري streams، حيث ينفّذ كائن http.IncomingMessage واجهة المجرى Stream القابلة للقراءة.

وحدة MySQL

تُعَدّ MySQL واحدةً من أكثر قواعد البيانات العلائقية شيوعًا في العالم، إذ يحتوي نظام نود Node المجتمعي على حزم مختلفة تتيح لك التعامل مع MySQL وتخزين البيانات واسترداد البيانات وما إلى ذلك، كما سنستخدِم حزمة mysqljs/mysql التي تحتوي على أكثر من 12000 نجمة على GitHub وهي موجودة منذ سنوات.

تثبيت حزمة نود mysql

يمكنك تثبيتها باستخدام الأمر التالي:

npm install mysql

تهيئة الاتصال بقاعدة البيانات

يجب تضمين الحزمة أولًا كما يلي:

const mysql = require('mysql')

ثم تنشئ اتصالًا كما يلي:

const options = {
  user: 'the_mysql_user_name',
  password: 'the_mysql_user_password',
  database: 'the_mysql_database_name'
}
  const connection = mysql.createConnection(options)

ثم تهيئ اتصالًا جديدًا عن طريق استدعاء ما يلي:

connection.connect(err => {
  if (err) {
    console.error('An error occurred while connecting to the DB')
    throw err
  }
})

خيارات الاتصال

احتوى كائن options في المثال السابق على 3 خيارات هي:

const options = {
  user: 'the_mysql_user_name',
  password: 'the_mysql_user_password',
  database: 'the_mysql_database_name'
}

هناك خيارات أخرى متعددة يمكنك استخدامها مثل:

  • host: اسم مضيف قاعدة البيانات، وقيمته الافتراضية هي localhost.
  • port رقم منفذ خادم MySQL، وقيمته الافتراضية هي 3306.
  • socketPath: يُستخدَم لتحديد مقبس يونيكس unix بدلًا من host وport.
  • debug: يمكن استخدامه لتنقيح الأخطاء debugging عند تعطيله افتراضيًا.
  • trace: يطبع تعقبات المكدس stack traces عند حدوث الأخطاء عند تفعيله افتراضيًا.
  • ssl: يُستخدَم لإعداد اتصال SSL إلى الخادم.

إجراء استعلام SELECT

أصبحتَ الآن جاهزًا لإجراء استعلام SQL في قاعدة البيانات، وسيستدعي الاستعلامُ بمجرد تنفيذه دالةَ رد النداء التي تحتوي على الخطأ المُحتمَل error والنتائج results والحقول fields كما يلي:

connection.query('SELECT * FROM todos', (error, todos, fields) => {
  if (error) {
    console.error('An error occurred while executing the query')
    throw error
  }
    console.log(todos)
 })

يمكنك تمرير القيم التي ستُتجاوز تلقائيًا كما يلي:

const id = 223
connection.query('SELECT * FROM todos WHERE id = ?', [id], (error, todos, fields) => {
  if (error) {
    console.error('An error occurred while executing the query')
    throw error
  }
  console.log(todos)
})

يمكنك تمرير قيم متعددة من خلال وضع مزيد من العناصر في المصفوفة التي تمررها على أساس معامل ثانٍ كما يلي:

const id = 223
const author = 'Flavio'
connection.query('SELECT * FROM todos WHERE id = ? AND author = ?', [id, author], (error,
todos, fields) => {
  if (error) {
    console.error('An error occurred while executing the query')
    throw error
  }
  console.log(todos)
})

إجراء استعلام INSERT

يمكنك تمرير كائن كما يلي:

const todo = {
  thing: 'Buy the milk'
  author: 'Flavio'
}
connection.query('INSERT INTO todos SET ?', todo, (error, results, fields) => {
  if (error) {
    console.error('An error occurred while executing the query')
    throw error
  }
})

إذا احتوى الجدول على مفتاح رئيسي primary key مع auto_increment، فستُعاد قيمته ضمن القيمة results.insertId كما يلي:

const todo = {
  thing: 'Buy the milk'
  author: 'Flavio'
}
connection.query('INSERT INTO todos SET ?', todo, (error, results, fields) => {
  if (error) {
    console.error('An error occurred while executing the query')
    throw error
  }}
  const id = results.resultId
  console.log(id)
)

إغلاق الاتصال

يمكنك استدعاء التابع end()‎ عند إنهاء الاتصال بقاعدة البيانات كما يلي:

connection.end()

يعمل ذلك على التأكد من إرسال أي استعلام مُعلَّق وإنهاء الاتصال بأمان.

وحدات مخصصة

إذا لم تعثر على الوحدات المناسبة لك ضمن الوحدات الأساسية، فيمكنك بناء وحدة مخصَّصة تخدم غرضك بالاعتماد على الوحدات الأساسية ويمكنك أن تصدِّرها وتستوردها حتى أنه يمكنك بناء مكتبة كاملة، حيث سنتعرّف فيما يلي على كيفية استخدام واجهة module.exports البرمجية لتصدير بياناتك إلى ملفات أخرى في تطبيقك أو إلى تطبيقات أخرى.

يمتلك نود نظام وحدات مبنيّ مسبقًا، إذ يمكن لملف Node.js استيراد العمليات التي تصدّرها ملفات Node.js الأخرى، فإذا أردت استيراد شيءٍ ما، فاستخدم ما يلي لاستيراد العمليات الظاهرة في ملف library.js الموجود في مجلد الملف الحالي، إذ يجب إظهار العمليات في هذا الملف قبل أن تستوردها ملفات أخرى:

const library = require('./library')

يكون أيّ كائن أو متغير آخر مُعرَّف في الملف خاصًا private افتراضيًا ولا يظهر لأيّ شيء خارجي، وهذا ما تسمح لنا به واجهة برمجة تطبيقات module.exports التي يوفِّرها [نظام module](https://nodejs.org/api/modules.html)، وإذا أسندتَ كائنًا أو دالةً مثل خاصية exports جديدة، فهذا هو الشيء الذي يظهر، ويمكن استيراده على هذا النحو في أجزاء أخرى من تطبيقك أو في تطبيقات أخرى أيضًا، حيث يمكنك تطبيق ذلك بطريقتين، الأولى هي إسناد كائن لوحدة module.exports، وهو كائن خارجي يوفّره نظام module، وبالتالي سيصدّر ملفك هذا الكائن فقط:

const car = {
  brand: 'Ford',
  model: 'Fiesta'
}

module.exports = car

//في الملف الآخر‫..

const car = require('./car')

أما الطريقة الثانية فهي إضافة الكائن المُصدَّر على أساس خاصية exports، حيث تتيح لك هذه الطريقة تصدير كائنات أو دوال أو بيانات متعددة:

const car = {
  brand: 'Ford',
  model: 'Fiesta'
}

exports.car = car

أو مباشرةً:

const car = {
  brand: 'Ford',
  model: 'Fiesta'
}

كما ستستخدمه في الملف الآخر من خلال الإشارة إلى خاصية الاستيراد كما يلي:

const items = require('./items')
items.car

أو كما يلي:

const car = require('./items').car

هناك فرق بين module.exports وexports، فالأول يُظهِر الكائن الذي يؤشّر إليه، بينما يُظهِر الثاني خاصيات الكائن الذي يؤشّر إليه.

ترجمة -وبتصرّف- للفصل Some essential core modules من كتاب The Node.js handbook لصاحبه Flavio Copes.

اقرأ أيضًا


تفاعل الأعضاء

أفضل التعليقات

لا توجد أية تعليقات بعد



انضم إلى النقاش

يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.

زائر
أضف تعليق

×   لقد أضفت محتوى بخط أو تنسيق مختلف.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   جرى استعادة المحتوى السابق..   امسح المحرر

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • أضف...