دليل المبتدئين لتطوير خادم الويب مع Node.js

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

هذا المنشور هو وصف لكيفية معرفة المزيد عن تطوير الويب من جانب الخادم باستخدام Node.js ، ومقارنة مختصرة لكتابة خادم HTTP بسيط باستخدام 3 بيئات مختلفة ، Express و Koa.js و Hapi.js.

ملاحظة: إذا كنت مطورًا ذو خبرة Node.js ، فربما تعتقد أن هذا كل شيء أساسي / بسيط. ¯ \ _ (ツ) _ / ¯.

بعض أساسيات الشبكة


عندما بدأت العمل في صناعة الويب قبل عامين ، صادفت دورة تدريبية على شبكات الكمبيوتر للأستاذ ديفيد فيتيرال في كورسيرا. لسوء الحظ ، لم تعد متوفرة ، لكن المحاضرات لا تزال متاحة على موقع بيرسون .

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

الصورة

هنا ، ومع ذلك ، سأتحدث فقط لفترة وجيزة عن السياق. HTTP (بروتوكول نقل النص التشعبي) هو بروتوكول اتصال يستخدم في شبكات الكمبيوتر. هناك الكثير على الإنترنت ، مثل SMTP (بروتوكول نقل البريد البسيط) ، FTP (بروتوكول نقل الملفات) ، POP3 (بروتوكول مكتب البريد 3) ، وهلم جرا.

تسمح هذه البروتوكولات للأجهزة ذات الأجهزة / البرامج المختلفة تمامًا بالتواصل مع بعضها البعض ، لأنها توفر تنسيقات وقواعد وصياغة ودلالات واضحة المعالم للرسائل ، إلخ. هذا يعني أنه بينما يدعم الجهاز بروتوكولًا محددًا ، يمكنه التواصل مع أي جهاز آخر. على النت

الصورة
من TCP / IP مقابل OSI: ما هو الفرق بين النموذجين؟

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

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

الصورة

الخوادم والعملاء


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

اليوم سنتحدث عن جانب البرنامج من الأشياء. لكن أولاً ، بعض التعاريف. يرمز URL إلى Universal Resource Locator ويتألف من 3 أجزاء: البروتوكول والخادم والملف المطلوب .

الصورة
هيكل URL

يعرّف بروتوكول HTTP العديد من الطرق التي يمكن للمتصفح استخدامها لمطالبة الخادم بتنفيذ مجموعة من الإجراءات المختلفة ، وأكثرها شيوعًا هي GET و POST. عندما ينقر المستخدم على رابط أو يدخل عنوان URL في شريط العناوين ، يرسل المتصفح طلب GET إلى الخادم لاسترداد المورد المحدد في عنوان URL.

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

الصورة
تقوم خوادم الويب بمعالجة الطلبات الواردة والرد عليها وفقًا لذلك

كلاهما عبارة عن حزم برامج مفتوحة المصدر كاملة الميزات تتضمن ميزات مثل أنظمة المصادقة وإعادة كتابة عنوان URL والتسجيل والوكيل ، على سبيل المثال لا الحصر. تتم كتابة Apache و NGINX باللغة C. تقنيًا ، يمكنك كتابة خادم ويب بأي لغة. Python ، golang.org/pkg/net/http ، روبي ، هذه القائمة يمكن أن تستمر لبعض الوقت. إن بعض اللغات تفعل أشياء معينة أفضل من غيرها.

إنشاء خادم HTTP مع Node.js


Node.js هو وقت تشغيل Javascript مبني على محرك Chrome V8 Javascript . يأتي مع وحدة http ، التي توفر مجموعة من الوظائف والفئات لبناء خادم HTTP.

بالنسبة لخادم HTTP الأساسي هذا ، سوف نستخدم أيضًا نظام الملفات والمسار وعنوان URL ، وهي وحدات Node.js أصلية.

ابدأ باستيراد الوحدات المطلوبة.

const http = require('http') //   HTTP-  Node.js const fs = require('fs') //      const path = require('path') //        const url = require('url') //     URL 

سنقوم أيضًا بإنشاء قاموس نوع MIME حتى نتمكن من تعيين نوع MIME المناسب إلى المورد المطلوب بناءً على امتداده. يمكن العثور على قائمة كاملة بأنواع MIME في هيئة أرقام الإنترنت المخصصة .

 const mimeTypes = { '.html': 'text/html', '.js': 'text/javascript', '.css': 'text/css', '.ico': 'image/x-icon', '.png': 'image/png', '.jpg': 'image/jpeg', '.gif': 'image/gif', '.svg': 'image/svg+xml', '.json': 'application/json', '.woff': 'font/woff', '.woff2': 'font/woff2' } 

الآن يمكننا إنشاء خادم HTTP مع وظيفة http.createServer() ، والتي ستعيد نسخة جديدة من http.Server .

 const server = http.createServer() 

سنقوم بتمرير وظيفة معالج الطلب إلى createServer() مع كائنات الطلب والاستجابة. تسمى هذه الوظيفة مرة واحدة في كل مرة يصل فيها طلب HTTP إلى الخادم.

 server.on('request', (req, res) => { //     }) 

يتم تشغيل الخادم عن طريق استدعاء طريقة listen الخاصة بكائن server برقم المنفذ الذي نريد أن يستمع إليه الخادم ، على سبيل المثال ، 5000 .

 server.listen(5000) 

كائن request هو مثيل لـ IncomingMessage ويسمح لنا بالوصول إلى جميع المعلومات حول الطلب ، مثل حالة الاستجابة والرؤوس والبيانات.

كائن response هو مثيل ServerResponse ، وهو دفق قابل للكتابة ويوفر العديد من الطرق لإرسال البيانات مرة أخرى إلى العميل.

في معالج الاستعلام ، نريد القيام بما يلي:

  • تحليل الطلب الوارد ومعالجته دون ملحقات

     const parsedUrl = new URL(req.url, 'https://node-http.glitch.me/') let pathName = parsedUrl.pathname let ext = path.extname(pathName) //   URL    '/',   '/' //      URL    'Location' if (pathName !== '/' && pathName[pathName.length - 1] === '/') { res.writeHead(302, {'Location': pathName.slice(0, -1)}) res.end() return } //     ,  index.html //     «.html»       if (pathName === '/') { ext = '.html' pathName = '/index.html' } else if (!ext) { ext = '.html' pathName += ext } 

  • قم بإجراء بعض الاختبارات الأولية لتحديد ما إذا كان المورد المطلوب موجودًا والرد وفقًا لذلك

     //     ,       const filePath = path.join(process.cwd(), '/public', pathName) // ,       fs.exists(filePath, function (exists, err) { //     ,  404 Not Found if (!exists || !mimeTypes[ext]) { console.log('  : ' + pathName) res.writeHead(404, {'Content-Type': 'text/plain'}) res.write('404 Not Found') res.end() return } //        200 OK, //       res.writeHead(200, {'Content-Type': mimeTypes[ext]}) //        const fileStream = fs.createReadStream(filePath) fileStream.pipe(res) }) 


تتم استضافة جميع الأكواد على Glitch ، ويمكنك إعادة مزج المشروع إذا أردت.

https://glitch.com/edit/#!/node-http

إنشاء خادم HTTP باستخدام إطارات Node.js


تأتي إطارات Node.js مثل Express و Koa.js و Hapi.js مع العديد من ميزات البرامج الوسيطة المفيدة ، بالإضافة إلى العديد من الميزات المفيدة الأخرى التي توفر للمطورين من الحاجة إلى الكتابة لأنفسهم.

أنا شخصياً أشعر أنه من الأفضل أن تتعلم أولاً الأساسيات بدون أطر ، فقط لفهم ما يحدث تحت الغطاء ، ثم تغضب من أي إطار تريده.

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

 const express = require('express') const app = express() //         app.use(express.static('public')) //  index.html,      //     res.sendFile() app.get('/', (req, res) => { res.sendFile(__dirname + '/public/index.html') }) app.listen(5000) 

لا يحتوي Koa.js على مكون إضافي مماثل داخل جوهره ، لذلك يجب تثبيت أي مكون إضافي مطلوب بشكل منفصل. يستخدم أحدث إصدار من Koa.js وظائف غير متزامنة لصالح عمليات الاسترجاعات. يمكنك استخدام البرنامج المساعد koa-static لخدمة الملفات الثابتة.

 const serve = require('koa-static') const koa = require('koa') const app = new koa() //         //   koa-static    index.html    app.use(serve(__dirname + '/public')) app.listen(5000) 

Hapi.js يدعم التخصيص ويدور حول تخصيص كائن server . يستخدم المكونات الإضافية لتوسيع ميزات مثل التوجيه والمصادقة وما إلى ذلك. لخدمة الملفات الثابتة ، نحتاج إلى برنامج إضافي يسمى inert .

 const path = require('path') const hapi = require('hapi') const inert = require('inert') //        const server = new hapi.Server({ port: 5000, routes: { files: { relativeTo: path.join(__dirname, 'public') } } }) const init = async () => { // server.register()      await server.register(inert) // inert     //       server.route({ method: 'GET', path: '/{param*}', handler: { directory: { path: '.', redirectToSlash: true, index: true } } }) await server.start() } init() 

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

الانتهاء


إذا كان جانب شبكة الأشياء دائمًا مربعًا أسودًا لك ، آمل أن تكون هذه المقالة بمثابة مقدمة مفيدة للبروتوكول الذي يوفر الشبكة. كما أوصي بشدة بقراءة وثائق واجهة برمجة تطبيقات Node.js ، وهي مكتوبة جيدًا ومفيدة جدًا لأي مبتدئ في Node.js بشكل عام.

Source: https://habr.com/ru/post/ar435970/


All Articles