Node.js هو نظام أساسي للخادم. تتمثل المهمة الرئيسية للخادم في معالجة الطلبات الواردة من العملاء ، على وجه الخصوص ، من المتصفحات ، بأسرع ما يمكن وبكفاءة. الثامنة من ترجمة البرنامج التعليمي Node.js التي ننشرها اليوم تدور حول HTTP و WebSocket.

[ننصحك بقراءة] أجزاء أخرى من الدورة ماذا يحدث عند إجراء طلبات HTTP؟
دعنا نتحدث عن كيفية قيام المستعرضات بتقديم طلبات إلى الخوادم باستخدام بروتوكول HTTP / 1.1.
إذا كانت لديك مقابلة في مجال تكنولوجيا المعلومات ، فقد يتم سؤالك عما يحدث عندما تكتب شيئًا في شريط عنوان المتصفح الخاص بك وتضغط على Enter. ربما يكون هذا أحد الأسئلة الأكثر شيوعًا التي تحدث في مثل هذه المقابلات. أي شخص يطرح مثل هذه الأسئلة يريد أن يعرف ما إذا كان بإمكانك شرح بعض المفاهيم البسيطة ومعرفة ما إذا كنت تفهم مبادئ الإنترنت.
يتطرق هذا السؤال إلى العديد من التقنيات ، لفهم المبادئ العامة التي تعني فهم كيفية بناء أحد أكثر الأنظمة المعقدة التي تم بناؤها على الإطلاق من قبل البشرية ، والتي تغطي العالم كله.
protocol بروتوكول HTTP
يمكن للمتصفحات الحديثة التمييز بين عناوين URL الحقيقية التي تم إدخالها في شريط العناوين الخاص بها من استعلامات البحث ، والتي يتم عادةً معالجتها باستخدام محرك البحث الافتراضي. سنتحدث عن عناوين URL. إذا قمت بإدخال عنوان موقع ويب ، مثل
flaviocopes.com
، في سطر المستعرض ،
flaviocopes.com
المستعرض بتحويل هذا العنوان إلى النموذج
http://flaviocopes.com
، بناءً على افتراض أن بروتوكول HTTP سيتم استخدامه لتبادل البيانات مع المورد المحدد. يرجى ملاحظة أنه على نظام التشغيل Windows ، قد يبدو ما سنتحدث عنه هنا مختلفًا قليلاً عن نظامي macOS و Linux.
look مرحلة بحث DNS
لذا ، يقوم المتصفح ، الذي يبدأ العمل على تنزيل البيانات من العنوان الذي يطلبه المستخدمون ، بعملية بحث DNS (بحث DNS) من أجل معرفة عنوان IP للخادم المقابل. تعتبر الأسماء الرمزية للموارد التي يتم إدخالها في شريط العناوين ملائمة للأشخاص ، ولكن جهاز الإنترنت يشير إلى إمكانية تبادل البيانات بين أجهزة الكمبيوتر باستخدام عناوين IP ، وهي مجموعات من الأرقام مثل 222.324.3.1 (لـ IPv4).
أولاً ، عند اكتشاف عنوان IP الخاص بالخادم ، يبحث المستعرض في ذاكرة التخزين المؤقتة لـ DNS المحلية لمعرفة ما إذا تم تنفيذ إجراء مماثل مؤخرًا. في متصفح Chrome ، على سبيل المثال ، هناك طريقة ملائمة للنظر في ذاكرة التخزين المؤقت لنظام أسماء النطاقات عن طريق إدخال العنوان التالي في شريط العنوان:
chrome://net-internals/#dns
.
إذا لم يتم العثور على أي شيء في ذاكرة التخزين المؤقت ، يستخدم المتصفح استدعاء نظام POSIX
gethostbyname
لمعرفة عنوان IP للخادم.
▍ دالة gethostbyname
تتحقق وظيفة
gethostbyname
أولاً من
hosts
، الذي يمكن العثور عليه على
/etc/hosts
على macOS أو Linux من أجل معرفة ما إذا كان يمكن العثور على المعلومات المحلية من خلال معرفة عنوان الخادم.
إذا فشلت الوسائل المحلية لحل الطلب لمعرفة عنوان IP للخادم ، فسيقوم النظام بطلب لخادم DNS. يتم تخزين عناوين هذه الخوادم في إعدادات النظام.
فيما يلي اثنين من خوادم DNS الشهيرة:
- 8.8.8.8: خادم Google DNS.
- 1.1.1.1: خادم DNS CloudFlare.
يستخدم معظم الأشخاص خوادم نظام أسماء النطاقات التي يوفرها مقدمو الخدمة. يقوم المستعرض بإجراء استعلامات DNS باستخدام بروتوكول UDP.
يعد TCP و UDP بروتوكولين أساسيين يستخدمان في شبكات الكمبيوتر. توجد في نفس المستوى المفاهيمي ، لكن TCP هو بروتوكول موجه للاتصال ، ولتبادل رسائل UDP ، التي تؤدي معالجتها إلى إنشاء حمل إضافي صغير على النظام ، لا يلزم إجراء إنشاء اتصال. لن نتحدث عن كيفية تبادل البيانات عبر UDP بالضبط.
قد يكون عنوان IP المقابل لاسم المجال الذي يهمنا موجودًا في ذاكرة التخزين المؤقت لخادم DNS. إذا لم يكن الأمر كذلك ، فسوف يتصل بخادم DNS الجذر. يتكون نظام خادم DNS الجذر من 13 خادمًا ، يعتمد عليها تشغيل الإنترنت بالكامل.
وتجدر الإشارة إلى أن خادم DNS الجذر لا يعرف المراسلات بين جميع أسماء النطاقات وعناوين IP الموجودة في العالم. لكن الخوادم المماثلة تعرف عناوين خوادم DNS عالية المستوى لنطاقات مثل .com و .it و. pizza وما إلى ذلك.
عند استلام الطلب ، يقوم خادم DNS الجذر بإعادة توجيهه إلى خادم DNS لنطاق المستوى الأعلى ، إلى ما يسمى بخادم TLD (من نطاق المستوى الأعلى).
لنفترض أن المتصفح يبحث عن عنوان IP لخادم
flaviocopes.com
. بالانتقال إلى خادم DNS الجذر ، سيتلقى المتصفح عنوان خادم TLD لمنطقة .com منه. الآن سيتم تخزين هذا العنوان في ذاكرة التخزين المؤقت ، ونتيجة لذلك ، إذا كنت بحاجة إلى معرفة عنوان IP لعنوان URL آخر من منطقة .com ، فلن تضطر إلى الاتصال بخادم DNS الجذر مرة أخرى.
تحتوي خوادم TLD على عناوين IP لخوادم الأسماء (Name Server، NS) ، والتي يمكنك من خلالها معرفة عنوان IP من عنوان URL لدينا. من أين يحصل خادم NS على هذه المعلومات؟ والحقيقة هي أنه إذا قمت بشراء نطاق ، يرسل مسجل النطاق بيانات حوله إلى خوادم الأسماء. يتم تنفيذ إجراء مماثل ، على سبيل المثال ، عند تغيير الاستضافة.
عادةً ما تكون الخوادم المعنية مملوكة لمقدمي الاستضافة. كقاعدة ، للحماية من الفشل ، يتم إنشاء العديد من هذه الخوادم. على سبيل المثال ، قد يكون لديهم هذه العناوين:
- ns1.dreamhost.com
- ns2.dreamhost.com
- ns3.dreamhost.com
لمعرفة عنوان IP بواسطة URL ، في النهاية ، يلجأون إلى هذه الخوادم. يقومون بتخزين البيانات الفعلية حول عناوين IP.
الآن ، بعد أن تمكنا من معرفة عنوان IP وراء عنوان URL الذي تم إدخاله في شريط عنوان المتصفح ، ننتقل إلى الخطوة التالية من عملنا.
▍ إنشاء اتصال TCP
بعد معرفة عنوان IP للخادم ، يمكن للعميل بدء اتصال TCP به. في عملية إنشاء اتصال TCP ، يقوم العميل والخادم بإرسال بعض بيانات الخدمة لبعضهما البعض ، وبعد ذلك يمكنهما تبادل المعلومات. هذا يعني أنه بعد إنشاء الاتصال ، سيتمكن العميل من إرسال طلب إلى الخادم.
requestإرسال طلب
الطلب عبارة عن جزء نصي مُنظم وفقًا لقواعد البروتوكول المستخدم. وتتكون من ثلاثة أجزاء:
- سلسلة الاستعلام
- رأس الطلب.
- نص الطلب.
سلسلة الاستعلام
سلسلة الاستعلام هي سلسلة نصية واحدة تحتوي على المعلومات التالية:
- طريقة HTTP.
- عنوان المورد
- إصدار البروتوكول.
قد يبدو ، على سبيل المثال ، مثل هذا:
GET / HTTP/1.1
رأس الطلب
يتم تمثيل رأس الطلب بمجموعة من
:
. هناك حقلي رأس مطلوبان ، أحدهما
Host
والثاني هو
Connection
. الحقول المتبقية اختيارية.
قد يبدو العنوان كما يلي:
Host: flaviocopes.com Connection: close
يشير حقل
Host
إلى اسم المجال الذي يهتم به المستعرض. يعني حقل
Connection
، المعين
close
، أنه لا يلزم إبقاء الاتصال بين العميل والخادم مفتوحًا.
تتضمن رؤوس الطلبات الأخرى شائعة الاستخدام ما يلي:
Origin
Accept
Accept-Encoding
Cookie
Cache-Control
Dnt
في الواقع ، هناك الكثير.
ينتهي رأس الطلب بسلسلة فارغة.
نص الطلب
نص الطلب اختياري ؛ لا يتم استخدامه في طلبات GET. يتم استخدام نص الطلب في طلبات POST ، وكذلك في الطلبات الأخرى. قد يحتوي ، على سبيل المثال ، على بيانات بتنسيق JSON.
نظرًا لأننا نتحدث الآن عن طلب GET ، فسيكون نص الطلب فارغًا ، ولن نعمل معه.
▍ الإجابة
بعد أن يتلقى الخادم الطلب الذي أرسله العميل ، يقوم بمعالجته وإرسال استجابة إلى العميل.
يبدأ الرد برمز الحالة والرسالة المقابلة. إذا نجح الطلب ، فستبدو بداية الاستجابة كما يلي:
200 OK
إذا حدث خطأ ما ، فقد تكون هناك رموز أخرى. على سبيل المثال ، ما يلي:
404 Not Found
403 Forbidden
301 Moved Permanently
500 Internal Server Error
304 Not Modified
401 Unauthorized
علاوة على ذلك ، تحتوي الاستجابة على قائمة بعناوين HTTP ونص الاستجابة (والذي ، نظرًا لأن الطلب يتم تنفيذه بواسطة المتصفح ، سيكون رمز HTML).
تحليل HTML
بعد أن يتلقى المتصفح استجابة الخادم ، الذي يحتوي نصه على كود HTML ، يبدأ في تحليله ، مكررًا العملية المذكورة أعلاه لكل مورد مطلوب لتكوين الصفحة. وتشمل هذه الموارد ، على سبيل المثال ، ما يلي:
- ملفات CSS.
- صور
- رمز صفحة الويب (الرمز المفضل).
- ملفات JavaScript.
لا تنطبق الطريقة التي يعرض بها المتصفح الصفحة بالضبط على محادثتنا. الشيء الرئيسي الذي يهمنا هنا هو أن عملية طلب البيانات وتلقيها أعلاه لا تستخدم فقط لرمز HTML ، ولكن أيضًا لأي كائنات أخرى تم نقلها من الخادم إلى المتصفح باستخدام بروتوكول HTTP.
حول إنشاء خادم بسيط باستخدام Node.js
الآن ، بعد أن فحصنا عملية التفاعل بين المتصفح والخادم ، يمكنك إلقاء نظرة جديدة على قسم تطبيق First Node.js من
الجزء الأول من هذه السلسلة من المواد ، حيث وصفنا الرمز لخادم بسيط.
عمل طلبات HTTP باستخدام Node.js
لتنفيذ طلبات HTTP باستخدام Node.js ،
يتم استخدام الوحدة النمطية المناسبة. تستخدم الأمثلة أدناه وحدة
https . والحقيقة هي أنه في الظروف الحديثة ، كلما كان ذلك ممكنًا ، من الضروري استخدام بروتوكول HTTPS.
requests تنفيذ طلبات GET
فيما يلي مثال على تنفيذ طلب GET باستخدام Node.js:
const https = require('https') const options = { hostname: 'flaviocopes.com', port: 443, path: '/todos', method: 'GET' } const req = https.request(options, (res) => { console.log(`statusCode: ${res.statusCode}`) res.on('data', (d) => { process.stdout.write(d) }) }) req.on('error', (error) => { console.error(error) }) req.end()
طلب تنفيذ ▍POST
إليك كيفية تقديم طلب POST من Node.js:
const https = require('https') const data = JSON.stringify({ todo: 'Buy the milk' }) const options = { hostname: 'flaviocopes.com', port: 443, path: '/todos', method: 'POST', headers: { 'Content-Type': 'application/json', 'Content-Length': data.length } } const req = https.request(options, (res) => { console.log(`statusCode: ${res.statusCode}`) res.on('data', (d) => { process.stdout.write(d) }) }) req.on('error', (error) => { console.error(error) }) req.write(data) req.end()
UT استعلامات حذف و حذف
تنفيذ مثل هذه الطلبات يبدو مثل تنفيذ طلبات POST. والفرق الرئيسي ، بالإضافة إلى المحتوى الدلالي لهذه العمليات ، هو قيمة خاصية
method
لكائن
options
.
requests تنفيذ طلبات HTTP في Node.js باستخدام مكتبة Axios
Axios هي مكتبة JavaScript شائعة جدًا تعمل في كل من المتصفح (وهذا يشمل جميع المتصفحات الحديثة و IE ، بدءًا من IE8) ، وفي بيئة Node.js ، والتي يمكن استخدامها لتنفيذ طلبات HTTP.
تعتمد هذه المكتبة على الوعود ، ولديها بعض المزايا على الآليات القياسية ، على وجه الخصوص ، عبر واجهة برمجة التطبيقات جلب. من بين مزاياها ما يلي:
- دعم المتصفحات القديمة (تحتاج إلى تعبئة متعددة لاستخدام الجلب).
- القدرة على مقاطعة الطلبات.
- دعم تحديد مهلات الطلبات.
- حماية مدمجة ضد هجمات CSRF.
- دعم تحميل البيانات مع توفير معلومات عن تقدم هذه العملية.
- دعم تحويل بيانات JSON.
- وظائف في Node.js
التثبيت
يمكنك استخدام npm لتثبيت Axios:
npm install axios
يمكن تحقيق نفس التأثير مع الغزل:
yarn add axios
يمكنك توصيل المكتبة بالصفحة باستخدام
unpkg.com
:
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
Axios API
يمكنك عمل طلب HTTP باستخدام كائن
axios
:
axios({ url: 'https://dog.ceo/api/breeds/list/all', method: 'get', data: { foo: 'bar' } })
ولكن عادة ما يكون استخدام وسائل خاصة أكثر ملاءمة:
هذا مشابه لكيفية استخدام jQuery
$.get()
و
$.post()
$.get()
$.post()
بدلاً من
$.ajax()
$.post()
.
تقدم Axios طرقًا منفصلة لتنفيذ أنواع أخرى من طلبات HTTP ، التي لا تحظى بشعبية مثل GET و POST ، ولكنها لا تزال مستخدمة:
axios.delete()
axios.put()
axios.patch()
axios.options()
تحتوي المكتبة على طريقة لتنفيذ طلب مصمم لاستقبال رؤوس HTTP فقط ، بدون نص الاستجابة:
طلبات GET
Axios مريحة للاستخدام باستخدام بناء الجملة الحديثة المتزامن / في انتظار الانتظار. يستخدم المثال التالي من التعليمات البرمجية ، المصمم لـ Node.js ، المكتبة لتحميل قائمة سلالات الكلاب من
Dog API . هنا يتم تطبيق طريقة
axios.get()
ويتم حساب الصخور:
const axios = require('axios') const getBreeds = async () => { try { return await axios.get('https://dog.ceo/api/breeds/list/all') } catch (error) { console.error(error) } } const countBreeds = async () => { const breeds = await getBreeds() if (breeds.data.message) { console.log(`Got ${Object.entries(breeds.data.message).length} breeds`) } } countBreeds()
يمكن إعادة كتابة الشيء نفسه دون استخدام المتزامن / الانتظار ، وتطبيق الوعود:
const axios = require('axios') const getBreeds = () => { try { return axios.get('https://dog.ceo/api/breeds/list/all') } catch (error) { console.error(error) } } const countBreeds = async () => { const breeds = getBreeds() .then(response => { if (response.data.message) { console.log( `Got ${Object.entries(response.data.message).length} breeds` ) } }) .catch(error => { console.log(error) }) } countBreeds()
استخدام المعلمات في طلبات GET
قد يحتوي طلب GET على معلمات تبدو كما يلي في عنوان URL:
https:
عند استخدام Axios ، يمكن إجراء استعلام من هذا النوع على النحو التالي:
axios.get('https:
يمكن تحقيق نفس التأثير من خلال تعيين خاصية المعلمات في كائن بمعلمات:
axios.get('https://site.com/', { params: { foo: 'bar' } })
طلبات ما بعد
تنفيذ طلبات POST يشبه إلى حد كبير تنفيذ طلبات GET ، ولكن هنا ، بدلاً من طريقة
axios.post()
يتم استخدام طريقة
axios.post()
:
axios.post('https:
كوسيطة ثانية ، يقبل الأسلوب
post
كائنًا بمعلمات الطلب:
axios.post('https://site.com/', { foo: 'bar' })
استخدام بروتوكول WebSocket في Node.js
WebSocket هو بديل لـ HTTP ، ويمكن استخدامه لتنظيم تبادل البيانات في تطبيقات الويب. يسمح لك هذا البروتوكول بإنشاء قنوات اتصال ثنائية الاتجاه طويلة الأمد بين العميل والخادم. بعد إنشاء الاتصال ، تظل قناة الاتصال مفتوحة ، مما يضع التطبيق تحت تصرف اتصال سريع للغاية ، يتميز بوقت استجابة منخفض وحمل إضافي صغير على النظام.
بروتوكول WebSocket مدعوم من جميع المتصفحات الحديثة.
ferences اختلافات HTTP
HTTP و WebSocket هما بروتوكولات مختلفة جدًا تستخدم أساليب مختلفة لتبادل البيانات. يعتمد HTTP على نموذج "طلب - استجابة": يرسل الخادم بعض البيانات إلى العميل بعد طلبه. في حالة WebSocket ، يتم ترتيب كل شيء بشكل مختلف. وهي:
- يمكن للخادم إرسال رسائل إلى العميل بمبادرة منه ، دون انتظار طلب من العميل.
- يمكن للعميل والخادم تبادل البيانات في نفس الوقت.
- عند إرسال رسالة ، يتم استخدام كمية صغيرة جدًا من بيانات الخدمة. هذا ، على وجه الخصوص ، يؤدي إلى الكمون المنخفض في نقل البيانات.
بروتوكول WebSocket مناسب تمامًا للاتصالات في الوقت الفعلي عبر القنوات التي تظل مفتوحة لفترة طويلة. HTTP ، بدوره ، ممتاز لتنظيم جلسات الاتصال العرضية التي بدأها العميل. في الوقت نفسه ، تجدر الإشارة إلى أنه ، من وجهة نظر البرمجة ، من الأسهل بكثير تنفيذ تبادل البيانات باستخدام بروتوكول HTTP من استخدام بروتوكول WebSocket.
version نسخة محمية من بروتوكول WebSocket
هناك إصدار غير آمن من بروتوكول WebSocket (
ws://
URI مخطط) ، والذي يشبه ، من حيث الأمان ، بروتوكول
http://
. يجب تجنب استخدام
ws://
، مفضلاً إصدارًا آمنًا من البروتوكول -
wss://
.
▍ إنشاء اتصال WebSocket
لإنشاء اتصال WebSocket ، تحتاج إلى استخدام
المُنشئ المناسب:
const url = 'wss://myserver.com/something' const connection = new WebSocket(url)
بعد إنشاء اتصال ناجح ، يتم رفع الحدث
open
. يمكنك تنظيم هذا الحدث عن طريق تعيين وظيفة رد
onopen
لخاصية
onopen
لكائن
connection
:
connection.onopen = () => {
لمعالجة الأخطاء ، يتم استخدام معالج حدث
onerror
:
connection.onerror = error => { console.log(`WebSocket error: ${error}`) }
dataإرسال البيانات إلى الخادم
بعد فتح اتصال WebSocket بالخادم ، يمكنك إرسال البيانات إليه. يمكن القيام بذلك ، على سبيل المثال ، في
onopen
onopen:
connection.onopen = () => { connection.send('hey') }
data الحصول على البيانات من الخادم
لاستلام البيانات المرسلة باستخدام بروتوكول WebSocket من الخادم ، يمكنك تعيين
onmessage
onmessage ، والذي سيتم استدعاؤه عند استلام حدث
message
:
connection.onmessage = e => { console.log(e.data) }
▍ تنفيذ خادم WebSocket في بيئة Node.js
من أجل تنفيذ خادم WebSocket في بيئة Node.js ، يمكنك استخدام مكتبة
ws الشائعة. سنستخدمها لتطوير الخادم ، ولكنها مناسبة لإنشاء العملاء ، وكذلك لتنظيم التفاعل بين خادمين.
قم بتثبيت هذه المكتبة بتهيئة المشروع أولاً:
yarn init yarn add ws
كود خادم WebSocket الذي نحتاج إلى كتابته مضغوط جدًا:
constWebSocket = require('ws') const wss = newWebSocket.Server({ port: 8080 }) wss.on('connection', ws => { ws.on('message', message => { console.log(`Received message => ${message}`) }) ws.send('ho!') })
ننشئ هنا خادمًا جديدًا يستمع على المنفذ القياسي 8080 لبروتوكول WebSocket ويصف رد اتصال ، والذي ، عندما يتم إنشاء الاتصال ، يرسل رسالة
ho!
إلى العميل
ho!
وتطبع على وحدة التحكم رسالة تم تلقيها من العميل.
هنا مثال عملي لخادم WebSocket ،
وهنا عميل يمكنه التفاعل معه.
الملخص
تحدثنا اليوم عن آليات التواصل المدعومة من منصة Node.js ، ورسم أوجه التشابه مع الآليات المماثلة المستخدمة في المتصفحات. سيكون موضوعنا التالي العمل مع الملفات.
أعزائي القراء! هل تستخدم بروتوكول WebSocket في تطبيقات الويب الخاصة بك ، حيث تم إنشاء جانب الخادم باستخدام Node.js؟