تعرف على كيفية إنشاء واجهة برمجة تطبيقات للدردشة في الوقت الفعلي بالاستفادة من قوة WebSockets باستخدام NestJS.
NestJS هو إطار عمل شائع لبناء تطبيقات من جانب الخادم باستخدام Node.js. من خلال دعمه لـ WebSockets ، يعد NestJS مناسبًا تمامًا لتطوير تطبيقات الدردشة في الوقت الفعلي.
إذن ، ما هي WebSockets ، وكيف يمكنك إنشاء تطبيق دردشة في الوقت الفعلي في NestJS؟
ما هي مآخذ الويب؟
WebSockets عبارة عن بروتوكول للاتصال المستمر والثنائي الاتجاه في الوقت الفعلي بين العميل والخادم.
على عكس HTTP حيث يتم إغلاق الاتصال عند اكتمال دورة الطلب بين العميل والخادم ، يظل اتصال WebSocket مفتوحًا ولا يغلق حتى بعد إرجاع استجابة لـ طلب.
الصورة أدناه عبارة عن تصور لكيفية عمل اتصال WebSocket بين الخادم والعميل:
لتأسيس اتصال ثنائي الاتجاه ، يرسل العميل طلب مصافحة WebSocket إلى الخادم. تحتوي رؤوس الطلب على مفتاح WebSocket آمن (مفتاح Sec-WebSocket) و الترقية: WebSocket رأس التي جنبا إلى جنب مع الاتصال: ترقية يخبر header الخادم بترقية البروتوكول من HTTP إلى WebSocket ، وإبقاء الاتصال مفتوحًا. التعلم عن WebSockets في JavaScript يساعد على فهم المفهوم بشكل أفضل.
بناء واجهة برمجة تطبيقات الدردشة في الوقت الحقيقي باستخدام وحدة NestJS WebSocket
يوفر Node.js اثنين من تطبيقات WebSockets الرئيسية. الأول هو ث الذي يطبق WebSockets العارية. والثاني هو المقبس، والذي يوفر المزيد من الميزات عالية المستوى.
يحتوي NestJS على وحدات لكليهما المقبس و ث. تستخدم هذه المقالة ملف المقبس الوحدة النمطية لميزات WebSocket للتطبيق النموذجي.
الكود المستخدم في هذا المشروع متاح في ملف مستودع جيثب. يوصى باستنساخه محليًا لفهم بنية الدليل بشكل أفضل ومعرفة كيفية تفاعل جميع الرموز مع بعضها البعض.
إعداد المشروع والتثبيت
افتح محطتك وأنشئ تطبيق NestJS جديدًا باستخدام ملف عش جديد أمر (على سبيل المثال عش تطبيق الدردشة الجديد). يقوم الأمر بإنشاء دليل جديد يحتوي على ملفات المشروع. أنت الآن جاهز لبدء عملية التطوير.
قم بإعداد اتصال MongoDB
لاستمرار رسائل الدردشة في التطبيق ، تحتاج إلى قاعدة بيانات. تستخدم هذه المقالة قاعدة بيانات MongoDB لتطبيق NestJS الخاص بنا، وأسهل طريقة للركض هي قم بإعداد كتلة MongoDB في السحابة واحصل على عنوان موقع MongoDB الخاص بك. انسخ عنوان URL وقم بتخزينه كملف MONGO_URI متغير في الخاص بك .env ملف.
ستحتاج أيضًا إلى النمس لاحقًا عند إجراء استعلامات إلى MongoDB. قم بتثبيته عن طريق التشغيل npm تثبيت النمس في محطتك.
في ال src مجلد ، قم بإنشاء ملف يسمى mongo.config.ts ولصق الكود التالي فيه.
يستورد {تسجيل باسم} من"@ nestjs / config";
/**
* تكوين اتصال قاعدة بيانات مونغو
*/
يصدّرتقصير تسجيل باسم ("منجودب", () => {
مقدار ثابت {MONGO_URI} = process.env ؛ // من ملف env
يعود {
uri:`{MONGO_URI} دولار`,
};
});
مشروعك main.ts يجب أن يبدو الملف كالتالي:
يستورد {NestFactory} من"@ nestjs / core";
يستورد {AppModule} من"./app.module";
يستورد * مثل ملف تعريف الارتباط من"محلل ملفات تعريف الارتباط"
يستورد خوذة من'خوذة'
يستورد {المسجل ، ValidationPipe} من"@ nestjs / مشترك";
يستورد {setupSwagger} من"./utils/swagger";
يستورد {HttpExceptionFilter} من"./filters/http-exception.filter";غير متزامنوظيفةالتمهيد() {
مقدار ثابت التطبيق = انتظر NestFactory.create (AppModule، { كورس: حقيقي });
app.enableCors ({
أصل: '*',
أوراق اعتماد: حقيقي
})
app.use (cookieParser ())
app.useGlobalPipes (
جديد ValidationPipe ({
القائمة البيضاء: حقيقي
})
)
مقدار ثابت المسجل = جديد المسجل ('رئيسي')app.setGlobalPrefix ("api / v1")
app.useGlobalFilters (جديد HttpExceptionFilter ()) ،setupSwagger (التطبيق)
app.use (خوذة ())انتظر app.listen (AppModule.port)
// سجل المستندات
مقدار ثابت baseUrl = AppModule.getBaseUrl (تطبيق)
مقدار ثابت url = http: //$ {baseUrl}:$ {AppModule.port}`
logger.log (`وثائق API متاحة في $ {url}/docs`);
}
التمهيد () ؛
بناء وحدة الدردشة
لبدء استخدام ميزة الدردشة في الوقت الفعلي ، فإن الخطوة الأولى هي تثبيت حزم NestJS WebSockets. يمكن القيام بذلك عن طريق تشغيل الأمر التالي في الجهاز.
npm install @ nestjs / websockets @ nestjs / platform-socket.io @ types / socket.io
بعد تثبيت الحزم ، تحتاج إلى إنشاء وحدة الدردشات عن طريق تشغيل الأوامر التالية
nest g وحدة الدردشات
عش ز تحكم الدردشات
دردشات خدمة nest g
بمجرد الانتهاء من إنشاء الوحدة ، فإن الخطوة التالية هي إنشاء اتصال WebSockets في NestJS. إنشاء chat.gateway.ts ملف داخل ملف الدردشات المجلد ، هذا هو المكان الذي يتم فيه تنفيذ البوابة التي ترسل الرسائل وتستقبلها.
الصق الكود التالي في chat.gateway.ts.
يستورد {
الرسالة
الاشتراك
WebSocketGateway ،
WebSocketServer ،
} من"@ nestjs / websockets";
يستورد { الخادم } من"socket.io";
WebSocketGateway ()
يصدّرفصلبوابة الدردشة{
WebSocketServer ()
الخادم: الخادم ؛
// استمع إلى أحداث send_message
SubscribeMessage ("send_message")
listenForMessages (MessageBody () message: string) {
هذا.server.sockets.emit ('تلقي رسالة'، رسالة)؛
}
}
مصادقة المستخدمين المتصلين
تعد المصادقة جزءًا أساسيًا من تطبيقات الويب ، ولا تختلف عن تطبيق الدردشة. تم العثور على وظيفة مصادقة اتصالات العميل بالمقبس في chats.service.ts كما هو موضح هنا:
@ حقن ()
يصدّرفصلخدمة الدردشة{
البناء(خدمة المصادقة الخاصة: AuthService) {}غير متزامن getUserFromSocket (المقبس: مقبس) {
يترك auth_token = socket.handshake.headers.authorization ؛
// احصل على الرمز نفسه بدون "Bearer"
auth_token = auth_token.split (' ')[1];مقدار ثابت المستخدم = هذا.authService.getUserFromAuthenticationToken (
auth_token
);
لو (!مستخدم) {
يرميجديد WsException ('بيانات الاعتماد غير صالحة.');
}
يعود مستخدم؛
}
}
ال getUserFromSocket طريقة الاستخدامات getUserFromAuthenticationToken للحصول على المستخدم الذي قام بتسجيل الدخول حاليًا من رمز JWT من خلال استخراج رمز Bearer. ال getUserFromAuthenticationToken يتم تنفيذ الوظيفة في المصادقة. service.ts الملف كما هو موضح هنا:
عام غير متزامن getUserFromAuthenticationToken (الرمز المميز: سلسلة) {
مقدار ثابت الحمولة: JwtPayload = هذا.jwtService.verify (الرمز المميز ، {
سر: هذا.configService.get ("JWT_ACCESS_TOKEN_SECRET"),
});مقدار ثابت userId = payload.sub
لو (معرف المستخدم) {
يعودهذا.usersService.findById (معرف المستخدم) ،
}
}
يتم تمرير المقبس الحالي كمعامل إلى getUserFromSocket عندما مقبض طريقة بوابة الدردشة تنفذ OnGatewayConnection واجهه المستخدم. هذا يجعل من الممكن تلقي الرسائل والمعلومات حول المستخدم المتصل حاليًا.
يوضح الكود أدناه هذا:
// chat.gateway.ts
WebSocketGateway ()
يصدّرفصلبوابة الدردشةالأدواتOnGatewayConnection{
WebSocketServer ()
الخادم: الخادم ؛البناء(خدمة الدردشات الخاصة: خدمة الدردشة) {}
غير متزامن handleConnection (المقبس: Socket) {
انتظرهذا.chatsService.getUserFromSocket (مقبس)
}SubscribeMessage ("send_message")
غير متزامن listenForMessages (MessageBody () message: string،ConnectedSocket () socket: Socket) {
مقدار ثابت المستخدم = انتظرهذا.chatsService.getUserFromSocket (مقبس)
هذا.server.sockets.emit ('تلقي رسالة', {
رسالة،
مستخدم
});
}
}
يمكنك الرجوع إلى الملفات المتضمنة في نظام المصادقة أعلاه في ملف مستودع جيثب للاطلاع على الرموز الكاملة (بما في ذلك الواردات) ، من أجل فهم أفضل للتنفيذ.
الدردشات المستمرة في قاعدة البيانات
لكي يرى المستخدمون محفوظات الرسائل الخاصة بهم ، فأنت بحاجة إلى مخطط لتخزين الرسائل. قم بإنشاء ملف جديد يسمى message.schema.ts والصق الرمز أدناه بداخله (تذكر استيراد ملف مخطط المستخدم أو تحقق من المستودع لواحد).
يستورد { مستخدم } من"./../users/schemas/user.schema";
يستورد {Prop ، Schema ، SchemaFactory} من"@ nestjs / النمس";
يستورد نمس ، {مستند} من"النمس";يصدّر اكتب MessageDocument = رسالة & مستند ؛
@مخطط({
توجسون: {
حاصل: حقيقي,
ظاهريون: حقيقي,
},
الطوابع الزمنية: حقيقي,
})
يصدّرفصلرسالة{
@دعم({ مطلوب: حقيقي, فريد: حقيقي })
الرسالة: سلسلة@دعم({ يكتب: نمس. مخطط. أنواع. معرف الكائن، المرجع: 'مستخدم' })
المستخدم: المستخدم
}مقدار ثابت MessageSchema = SchemaFactory.createForClass (رسالة)
يصدّر {MessageSchema} ؛
يوجد أدناه تطبيق للخدمات لإنشاء رسالة جديدة والحصول على جميع الرسائل chats.service.ts.
يستورد {رسالة ، رسالة ، وثيقة} من"./message.schema";
يستورد { قابس كهرباء } من"socket.io";
يستورد {خدمة المؤلف} من"./../auth/auth.service";
يستورد {قابل للحقن} من"@ nestjs / مشترك";
يستورد {WsException} من"@ nestjs / websockets";
يستورد {InjectModel} من"@ nestjs / النمس";
يستورد { نموذج } من'النمس';
يستورد {MessageDto} من"./dto/message.dto";
@ حقن ()
يصدّرفصلخدمة الدردشة{
البناء(خدمة authService الخاصة: AuthService،InjectModel (Message.name) رسالة خاصة) {}
...
غير متزامن إنشاء رسالة (الرسالة: MessageDto ، معرف المستخدم: خيط) {
مقدار ثابت newMessage = جديدهذا.messageModel ({... message، userId})
انتظر newMessage.save
يعود رسالة جديدة
}
غير متزامن getAllMessages () {
يعودهذا.messageModel.find (). ملء ('مستخدم')
}
}
ال الرسالة يتم تنفيذه في message.dto.ts ملف في دتو مجلد في الدردشات الدليل. يمكنك أيضًا العثور عليه في المستودع.
تحتاج إلى إضافة رسالة نموذج ومخطط لقائمة الواردات في chats.module.ts.
يستورد {رسالة ، رسالة نصية} من"./message.schema";
يستورد { وحدة } من"@ nestjs / مشترك";
يستورد {ChatGateway} من"./chats.gateway";
يستورد {خدمة الدردشة} من"./chats.service";
يستورد {MongooseModule} من"@ nestjs / النمس";
@وحدة({
الواردات: [MongooseModule.forFeature ([
{ اسم: Message.name ، مخطط: MessageSchema}
])],
أجهزة التحكم: [] ،
الموفرون: [ChatsService، ChatGateway]
})
يصدّرفصلالدردشات{}
وأخيرا، فإن get_all_messages تتم إضافة معالج الأحداث إلى ملف بوابة الدردشة فئة في chat.gateway.ts كما هو موضح في الكود التالي:
// الواردات ...
WebSocketGateway ()
يصدّرفصلبوابة الدردشةالأدواتOnGatewayConnection{
...SubscribeMessage ("get_all_messages")
غير متزامن getAllMessages (ConnectedSocket () socket: Socket) {انتظرهذا.chatsService.getUserFromSocket (مقبس)
مقدار ثابت رسائل = انتظرهذا.chatsService.getAllMessages ()هذا.server.sockets.emit ('تلقي رسالة'، رسائل)؛
يعود رسائل
}
}
عندما يقوم عميل متصل (مستخدم) بإصدار ملف get_all_messages الحدث ، سيتم استرداد جميع رسائلهم ، وعندما يرسلون send_message ، يتم إنشاء رسالة وتخزينها في قاعدة البيانات ، ثم إرسالها إلى جميع العملاء المتصلين الآخرين.
بمجرد الانتهاء من جميع الخطوات المذكورة أعلاه ، يمكنك بدء التطبيق الخاص بك باستخدام بدء تشغيل npm: dev، واختبره مع عميل WebSocket مثل Postman.
بناء تطبيقات في الوقت الحقيقي باستخدام NestJS
على الرغم من وجود تقنيات أخرى لبناء أنظمة في الوقت الفعلي ، إلا أن WebSockets تحظى بشعبية كبيرة وسهلة التنفيذ في كثير من الحالات ، وهي الخيار الأفضل لتطبيقات الدردشة.
لا تقتصر تطبيقات الوقت الفعلي على تطبيقات الدردشة فحسب ، بل تشمل الأمثلة الأخرى دفق الفيديو أو تطبيقات الاتصال ، وتطبيقات الطقس الحية ، ويوفر NestJS أدوات رائعة لبناء الوقت الفعلي تطبيقات.