البرنامج التعليمي: إنشاء تطبيق دردشة باستخدام خدمة Azure Web PubSub
في البرنامج التعليمي نشر الرسائل والاشتراك فيها، ستتعلم أساسيات نشر الرسائل والاشتراك فيها باستخدام Azure Web PubSub. في هذا البرنامج التعليمي، ستتعلم نظام الأحداث في Azure Web PubSub وتستخدمه لإنشاء تطبيق ويب كامل مع وظائف الاتصال في الوقت الحقيقي.
في هذا البرنامج التعليمي، تتعلم كيفية:
- إنشاء مثيل خدمة Web PubSub
- قم بتكوين إعدادات معالج الأحداث لـ Azure Web PubSub
- معالجة الأحداث في خادم التطبيق وإنشاء تطبيق دردشة في الوقت الحقيقي
إذا لم يكن لديك اشتراك في Azure، فأنشئ حساب Azure مجاني قبل أن تبدأ.
المتطلبات الأساسية
استخدم بيئة Bash في Azure Cloud Shell. لمزيد من المعلومات، راجع التشغيل السريع ل Bash في Azure Cloud Shell.
إذا كنت تفضل تشغيل أوامر مرجع CLI محلياً قم بتثبيت CLI Azure. إذا كنت تعمل على نظام تشغيل Windows أو macOS، ففكر في تشغيل Azure CLI في حاوية Docker. لمزيد من المعلومات، راجع كيفية تشغيل Azure CLI في حاوية Docker.
إذا كنت تستخدم تثبيت محلي، يُرجى تسجيل الدخول إلى Azure CLI مستخدمًا أمر az login. لإنهاء عملية المصادقة، اتبع الخطوات المعروضة في جهازك. للحصول على خيارات أخرى لتسجيل دخول، راجع تسجيل الدخول باستخدام Azure CLI.
عندما يُطلب منك، قم بتثبيت ملحق Azure CLI عند الاستخدام لأول مرة. لمزيد من المعلومات بشأن الامتدادات، راجع استخدام امتدادات مع Azure CLI.
يُرجى تشغيل إصدار az للوصول إلى الإصدار والمكتبات التابعة التي تم تثبيتها. للتحديث لآخر إصدار، يُرجى تشغيل تحديث az.
- يتطلب هذا الإعداد الإصدار 2.22.0 أو أعلى من Azure CLI. إذا كنت تستخدم Azure Cloud Shell، يتم تثبيت أحدث إصدار بالفعل.
إنشاء مثيل Azure Web PubSub
إنشاء مجموعة موارد
وتُعد مجموعة الموارد عبارة عن حاوية منطقية يتم فيها توزيع موارد Azure وإدارتها.
استخدم الأمر az group create لإنشاء مجموعة موارد باسم myResourceGroup
في eastus
الموقع.
az group create --name myResourceGroup --location EastUS
إنشاء مثيل Web PubSub
قم بتشغيل ملحق az add لتثبيت أو ترقية ملحق webpubsub إلى الإصدار الحالي.
az extension add --upgrade --name webpubsub
استخدم الأمر Azure CLI az webpubsub create لإنشاء Web PubSub في مجموعة الموارد التي قمت بإنشائها. ينشئ الأمر التالي مورد Web PubSub مجاني ضمن مجموعة الموارد myResourceGroup في EastUS:
هام
يجب أن يكون لكل مورد Web PubSub ويب اسمًا فريدًا. استبدل <your-unique-resource-name> باسم Web PubSub في الأمثلة التالية.
az webpubsub create --name "<your-unique-resource-name>" --resource-group "myResourceGroup" --location "EastUS" --sku Free_F1
يظهر إخراج هذا الأمر خصائص المورد المنشأ حديثًا. دوّن اثنتين من الخصائص المذكورة أدناه:
-
اسم المورد: الاسم الذي قدمته للمعلمة
--name
أعلاه. -
اسم المضيف: في المثال، اسم المضيف هو
<your-unique-resource-name>.webpubsub.azure.com/
.
في هذه المرحلة، حساب Azure هو الوحيد المصرح به لتنفيذ أي عمليات على هذا المورد الجديد.
احصل على ConnectionString لاستخدامها في المستقبل
هام
تظهر سلسلة الاتصال الأولية في هذه المقالة لأغراض العرض التوضيحي فقط.
سلسلة اتصال تتضمن معلومات التخويل المطلوبة لتطبيقك للوصول إلى خدمة Azure Web PubSub. مفتاح الوصول داخل سلسلة الاتصال يشبه كلمة مرور الجذر للخدمة الخاصة بك. في بيئات الإنتاج، قم دائما بحماية مفاتيح الوصول الخاصة بك. استخدم Azure Key Vault لإدارة مفاتيحك وتدويرها بأمان وتأمين اتصالك ب WebPubSubServiceClient
.
تجنب توزيع مفاتيح الوصول إلى مستخدمين آخرين، أو ترميزها ترميزًا ثابتًا، أو حفظها في أي مكان في نص عادي يمكن للآخرين الوصول إليه. قم بتدوير المفاتيح الخاصة بك إذا كنت تعتقد أنها قد تعرضت للخطر.
استخدم الأمر Azure CLI az webpubsub key للحصول على ConnectionString للخدمة.
<your-unique-resource-name>
استبدل العنصر النائب باسم مثيل Azure Web PubSub.
az webpubsub key show --resource-group myResourceGroup --name <your-unique-resource-name> --query primaryConnectionString --output tsv
انسخ سلسلة الاتصال لاستخدامها لاحقا.
انسخ ConnectionString الذي تم إحضاره وقم بتعيينه إلى متغير WebPubSubConnectionString
البيئة ، والذي يقرأه البرنامج التعليمي لاحقا. استبدل <connection-string>
أدناه ب ConnectionString الذي أحضرته.
export WebPubSubConnectionString="<connection-string>"
SET WebPubSubConnectionString=<connection-string>
إعداد المشروع
المتطلبات الأساسية
قم بإنشاء التطبيق
في Azure Web PubSub، هناك دوران، الخادم والعميل. يشبه هذا المفهوم أدوار الخادم والعميل في تطبيق الويب. الخادم مسؤول عن إدارة العملاء والاستماع والرد على رسائل العميل. العميل مسؤول عن إرسال رسائل المستخدم وتلقيها من الخادم وتصورها للمستخدم النهائي.
في هذا البرنامج التعليمي، نقوم بإنشاء تطبيق ويب للدردشة في الوقت الحقيقي. في تطبيق ويب حقيقي، تتضمن مسؤولية الخادم أيضاً مصادقة العملاء وخدمة صفحات الويب الثابتة لواجهة مستخدم التطبيق.
نستخدم ASP.NET Core 8 لاستضافة صفحات الويب ومعالجة الطلبات الواردة.
أولا دعونا ننشئ تطبيق ويب ASP.NET Core في chatapp
مجلد.
إنشاء تطبيق ويب جديد.
mkdir chatapp cd chatapp dotnet new web
أضف
app.UseStaticFiles()
Program.cs لدعم استضافة صفحات ويب ثابتة.var builder = WebApplication.CreateBuilder(args); var app = builder.Build(); app.UseStaticFiles(); app.Run();
أنشئ ملف HTML واحفظه باسم
wwwroot/index.html
، ونستخدمه لواجهة مستخدم تطبيق الدردشة لاحقا.<html> <body> <h1>Azure Web PubSub Chat</h1> </body> </html>
يمكنك اختبار الخادم عن طريق تشغيل dotnet run --urls http://localhost:8080
والوصول http://localhost:8080/index.html
في المستعرض.
إضافة نقطة نهاية التفاوض
في البرنامج التعليمي نشر ورسالة الاشتراك، يستهلك المشترك سلسلة الاتصال مباشرة. في تطبيق العالم الحقيقي، ليس من الآمن مشاركة سلسلة الاتصال مع أي عميل، لأن سلسلة الاتصال لديه امتياز كبير للقيام بأي عملية للخدمة. الآن، لنجعل الخادم الخاص بك يستهلك سلسلة الاتصال، ويعرض negotiate
نقطة نهاية للعميل للحصول على عنوان URL الكامل مع رمز الوصول المميز. وبهذه الطريقة، يمكن للخادم إضافة برنامج وسيط المصادقة قبل negotiate
نقطة النهاية لمنع الوصول غير المصرح به.
قم أولا بتثبيت التبعيات.
dotnet add package Microsoft.Azure.WebPubSub.AspNetCore
الآن دعونا نضيف /negotiate
نقطة نهاية للعميل لاستدعاء لإنشاء الرمز المميز.
using Azure.Core;
using Microsoft.Azure.WebPubSub.AspNetCore;
using Microsoft.Azure.WebPubSub.Common;
using Microsoft.Extensions.Primitives;
// Read connection string from environment
var connectionString = Environment.GetEnvironmentVariable("WebPubSubConnectionString");
if (connectionString == null)
{
throw new ArgumentNullException(nameof(connectionString));
}
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddWebPubSub(o => o.ServiceEndpoint = new WebPubSubServiceEndpoint(connectionString))
.AddWebPubSubServiceClient<Sample_ChatApp>();
var app = builder.Build();
app.UseStaticFiles();
// return the Client Access URL with negotiate endpoint
app.MapGet("/negotiate", (WebPubSubServiceClient<Sample_ChatApp> service, HttpContext context) =>
{
var id = context.Request.Query["id"];
if (StringValues.IsNullOrEmpty(id))
{
context.Response.StatusCode = 400;
return null;
}
return new
{
url = service.GetClientAccessUri(userId: id).AbsoluteUri
};
});
app.Run();
sealed class Sample_ChatApp : WebPubSubHub
{
}
AddWebPubSubServiceClient<THub>()
يستخدم لإدخال عميل WebPubSubServiceClient<THub>
الخدمة ، والذي يمكننا استخدامه في خطوة التفاوض لإنشاء رمز مميز لاتصال العميل وفي أساليب المركز لاستدعاء واجهات برمجة تطبيقات REST للخدمة عند تشغيل أحداث المركز. يشبه رمز إنشاء الرمز المميز الرمز الذي استخدمناه في البرنامج التعليمي لنشر الرسائل والاشتراك فيها، باستثناء أننا نمرر وسيطة أخرى (userId
) عند إنشاء الرمز المميز. يمكن استخدام معرف المستخدم لتحديد هوية العميل ومن ثم عندما تتلقى رسالة تعرف مصدرها.
تقرأ التعليمات البرمجية سلسلة الاتصال من متغير WebPubSubConnectionString
البيئة الذي قمنا بتعيينه في الخطوة السابقة.
أعد تشغيل الخادم باستخدام dotnet run --urls http://localhost:8080
.
يمكنك اختبار واجهة برمجة التطبيقات هذه عن طريق الوصول http://localhost:8080/negotiate?id=user1
وتمنحك عنوان URL الكامل ل Azure Web PubSub مع رمز مميز للوصول.
معالجة الأحداث
في Azure Web PubSub، عندما تحدث أنشطة معينة من جانب العميل (على سبيل المثال، يقوم العميل بالاتصال أو الاتصال أو قطع الاتصال أو إرسال العميل للرسائل)، ترسل الخدمة إعلامات إلى الخادم حتى يتمكن من التفاعل مع هذه الأحداث.
يتم تسليم الأحداث إلى الخادم في شكل Webhook. يتم تقديم خطاف الويب وعرضه بواسطة خادم التطبيق ويتم تسجيله في جانب خدمة Azure Web PubSub. تستدعي الخدمة خطافات الويب كلما وقع حدث.
يتبع Azure Web PubSub CloudEvents لوصف بيانات الحدث.
نعالج connected
أدناه أحداث النظام عندما يكون العميل متصلا ويتعامل مع message
أحداث المستخدم عندما يرسل العميل رسائل لإنشاء تطبيق الدردشة.
يمكن أن يساعد Web PubSub SDK ل AspNetCore Microsoft.Azure.WebPubSub.AspNetCore
الذي قمنا بتثبيته في الخطوة السابقة أيضا في تحليل طلبات CloudEvents ومعالجتها.
أولا، أضف معالجات الأحداث قبل app.Run()
. حدد مسار نقطة النهاية للأحداث، وليكن مثلاً /eventhandler
.
app.MapWebPubSubHub<Sample_ChatApp>("/eventhandler/{*path}");
app.Run();
الآن، داخل الفئة Sample_ChatApp
التي أنشأناها في الخطوة السابقة، أضف منشئا للعمل معه WebPubSubServiceClient<Sample_ChatApp>
نستخدمه لاستدعاء خدمة Web PubSub. وللرد OnConnectedAsync()
عند connected
تشغيل الحدث، OnMessageReceivedAsync()
لمعالجة الرسائل من العميل.
sealed class Sample_ChatApp : WebPubSubHub
{
private readonly WebPubSubServiceClient<Sample_ChatApp> _serviceClient;
public Sample_ChatApp(WebPubSubServiceClient<Sample_ChatApp> serviceClient)
{
_serviceClient = serviceClient;
}
public override async Task OnConnectedAsync(ConnectedEventRequest request)
{
Console.WriteLine($"[SYSTEM] {request.ConnectionContext.UserId} joined.");
}
public override async ValueTask<UserEventResponse> OnMessageReceivedAsync(UserEventRequest request, CancellationToken cancellationToken)
{
await _serviceClient.SendToAllAsync(RequestContent.Create(
new
{
from = request.ConnectionContext.UserId,
message = request.Data.ToString()
}),
ContentType.ApplicationJson);
return new UserEventResponse();
}
}
في التعليمات البرمجية أعلاه، نستخدم عميل الخدمة لبث رسالة إعلام بتنسيق JSON لجميع من انضموا إلى SendToAllAsync
.
تحديث صفحة الويب
الآن دعنا نحدث index.html
لإضافة المنطق للاتصال وإرسال الرسائل وعرض الرسائل المستلمة في الصفحة.
<html>
<body>
<h1>Azure Web PubSub Chat</h1>
<input id="message" placeholder="Type to chat...">
<div id="messages"></div>
<script>
(async function () {
let id = prompt('Please input your user name');
let res = await fetch(`/negotiate?id=${id}`);
let data = await res.json();
let ws = new WebSocket(data.url);
ws.onopen = () => console.log('connected');
let messages = document.querySelector('#messages');
ws.onmessage = event => {
let m = document.createElement('p');
let data = JSON.parse(event.data);
m.innerText = `[${data.type || ''}${data.from || ''}] ${data.message}`;
messages.appendChild(m);
};
let message = document.querySelector('#message');
message.addEventListener('keypress', e => {
if (e.charCode !== 13) return;
ws.send(message.value);
message.value = '';
});
})();
</script>
</body>
</html>
يمكنك أن ترى في التعليمات البرمجية أعلاه التي نتصل بها استخدام واجهة برمجة تطبيقات WebSocket الأصلية في المستعرض، واستخدام WebSocket.send()
لإرسال رسالة والاستماع WebSocket.onmessage
إلى الرسائل المستلمة.
يمكنك أيضا استخدام Client SDKs للاتصال بالخدمة، ما يمكنك من إعادة الاتصال التلقائي ومعالجة الأخطاء والمزيد.
هناك الآن خطوة واحدة متبقية حتى تعمل الدردشة. لنقم بتكوين الأحداث التي نهتم بها ومكان إرسال الأحداث إليها في خدمة Web PubSub.
إعداد معالج الأحداث
قمنا بتعيين معالج الأحداث في خدمة Web PubSub لإخبار الخدمة بمكان إرسال الأحداث إليها.
عند تشغيل خادم الويب محليا، كيف تستدعي خدمة Web PubSub المضيف المحلي إذا لم يكن لديه نقطة نهاية يمكن الوصول إليها عبر الإنترنت؟ هناك عادة طريقتان. أحدهما هو كشف المضيف المحلي للجمهور باستخدام أداة نفق عامة، والآخر هو استخدام awps-tunnel لنفق نسبة استخدام الشبكة من خدمة Web PubSub من خلال الأداة إلى الخادم المحلي الخاص بك.
في هذا القسم، نستخدم Azure CLI لتعيين معالجات الأحداث واستخدام awps-tunnel لتوجيه نسبة استخدام الشبكة إلى localhost.
تكوين إعدادات المركز
قمنا بتعيين قالب URL لاستخدام tunnel
النظام بحيث يوجه Web PubSub الرسائل من خلال awps-tunnel
اتصال النفق. يمكن تعيين معالجات الأحداث إما من المدخل أو CLI كما هو موضح في هذه المقالة، هنا نعينها من خلال CLI. نظرا لأننا نستمع إلى الأحداث في المسار /eventhandler
كمجموعات الخطوات السابقة، نقوم بتعيين قالب url إلى tunnel:///eventhandler
.
استخدم الأمر Azure CLI az webpubsub hub create لإنشاء إعدادات معالج الأحداث للمركز Sample_ChatApp
.
هام
استبدل <your-unique-resource-name> باسم مورد Web PubSub الذي تم إنشاؤه من الخطوات السابقة.
az webpubsub hub create -n "<your-unique-resource-name>" -g "myResourceGroup" --hub-name "Sample_ChatApp" --event-handler url-template="tunnel:///eventhandler" user-event-pattern="*" system-event="connected"
تشغيل awps-tunnel محليا
تنزيل وتثبيت awps-tunnel
تعمل الأداة على Node.js الإصدار 16 أو أعلى.
npm install -g @azure/web-pubsub-tunnel-tool
استخدام سلسلة الاتصال الخدمة وتشغيلها
export WebPubSubConnectionString="<your connection string>"
awps-tunnel run --hub Sample_ChatApp --upstream http://localhost:8080
تشغيل خادم الويب
الآن تم تعيين كل شيء. دعونا نشغل خادم الويب ونلعب مع تطبيق الدردشة أثناء العمل.
الآن قم بتشغيل الخادم باستخدام dotnet run --urls http://localhost:8080
.
يمكنك الاطلاع على نموذج التعليمة البرمجية لهذا البرنامج التعليمي كاملاً من هنا.
افتح http://localhost:8080/index.html
. يمكنك إدخال اسم المستخدم وبدء الدردشة.
مصادقة كسولة مع connect
معالج الأحداث
في الأقسام السابقة، نوضح كيفية استخدام نقطة نهاية التفاوض لإرجاع عنوان URL لخدمة Web PubSub ورمز الوصول إلى JWT للعملاء للاتصال بخدمة Web PubSub. في بعض الحالات، على سبيل المثال، أجهزة الحافة التي تحتوي على موارد محدودة، قد يفضل العملاء الاتصال المباشر بموارد Web PubSub. في مثل هذه الحالات، يمكنك تكوين connect
معالج الأحداث لمصادقة العملاء البطيئة، وتعيين معرف المستخدم للعملاء، وتحديد المجموعات التي ينضم إليها العملاء بمجرد الاتصال، وتكوين الأذونات التي يمتلكها العملاء وWebSocket subprotocol كاستجابة WebSocket للعميل، وما إلى ذلك. يرجى الرجوع إلى التفاصيل لتوصيل مواصفات معالج الأحداث.
الآن دعونا نستخدم connect
معالج الأحداث لتحقيق ما يشبه ما يفعله قسم التفاوض .
تحديث إعدادات المركز
أولا دعونا نحدث إعدادات المركز لتضمين connect
معالج الأحداث أيضا، نحتاج أيضا إلى السماح بالاتصال المجهول بحيث يمكن للعملاء الذين لا يملكون رمز وصول JWT الاتصال بالخدمة.
استخدم الأمر Azure CLI az webpubsub hub update لإنشاء إعدادات معالج الأحداث للمركز Sample_ChatApp
.
هام
استبدل <your-unique-resource-name> باسم مورد Web PubSub الذي تم إنشاؤه من الخطوات السابقة.
az webpubsub hub update -n "<your-unique-resource-name>" -g "myResourceGroup" --hub-name "Sample_ChatApp" --allow-anonymous true --event-handler url-template="tunnel:///eventhandler" user-event-pattern="*" system-event="connected" system-event="connect"
تحديث منطق المصدر لمعالجة حدث الاتصال
الآن دعونا نحدث منطق المصدر لمعالجة حدث الاتصال. يمكننا أيضا إزالة نقطة نهاية التفاوض الآن.
كما هو الحال مع ما نقوم به في التفاوض على نقطة النهاية كغرض تجريبي، نقرأ أيضا المعرف من معلمات الاستعلام. في حدث الاتصال، يتم الاحتفاظ باستعلام العميل الأصلي في نص طلب حدث الاتصال.
داخل الفئة Sample_ChatApp
، تجاوز OnConnectAsync()
لمعالجة connect
الحدث:
sealed class Sample_ChatApp : WebPubSubHub
{
private readonly WebPubSubServiceClient<Sample_ChatApp> _serviceClient;
public Sample_ChatApp(WebPubSubServiceClient<Sample_ChatApp> serviceClient)
{
_serviceClient = serviceClient;
}
public override ValueTask<ConnectEventResponse> OnConnectAsync(ConnectEventRequest request, CancellationToken cancellationToken)
{
if (request.Query.TryGetValue("id", out var id))
{
return new ValueTask<ConnectEventResponse>(request.CreateResponse(userId: id.FirstOrDefault(), null, null, null));
}
// The SDK catches this exception and returns 401 to the caller
throw new UnauthorizedAccessException("Request missing id");
}
public override async Task OnConnectedAsync(ConnectedEventRequest request)
{
Console.WriteLine($"[SYSTEM] {request.ConnectionContext.UserId} joined.");
}
public override async ValueTask<UserEventResponse> OnMessageReceivedAsync(UserEventRequest request, CancellationToken cancellationToken)
{
await _serviceClient.SendToAllAsync(RequestContent.Create(
new
{
from = request.ConnectionContext.UserId,
message = request.Data.ToString()
}),
ContentType.ApplicationJson);
return new UserEventResponse();
}
}
تحديث index.html للاتصال المباشر
الآن دعونا نحدث صفحة الويب للاتصال المباشر بخدمة Web PubSub. هناك شيء واحد يجب الإشارة إليه هو أنه الآن لغرض العرض التوضيحي، يتم ترميز نقطة نهاية خدمة Web PubSub في التعليمات البرمجية للعميل، يرجى تحديث اسم <the host name of your service>
مضيف الخدمة في html أدناه بالقيمة من الخدمة الخاصة بك. قد لا يزال من المفيد إحضار قيمة نقطة نهاية خدمة Web PubSub من الخادم الخاص بك، فهو يمنحك المزيد من المرونة وإمكانية التحكم في المكان الذي يتصل به العميل.
<html>
<body>
<h1>Azure Web PubSub Chat</h1>
<input id="message" placeholder="Type to chat...">
<div id="messages"></div>
<script>
(async function () {
// sample host: mock.webpubsub.azure.com
let hostname = "<the host name of your service>";
let id = prompt('Please input your user name');
let ws = new WebSocket(`wss://${hostname}/client/hubs/Sample_ChatApp?id=${id}`);
ws.onopen = () => console.log('connected');
let messages = document.querySelector('#messages');
ws.onmessage = event => {
let m = document.createElement('p');
let data = JSON.parse(event.data);
m.innerText = `[${data.type || ''}${data.from || ''}] ${data.message}`;
messages.appendChild(m);
};
let message = document.querySelector('#message');
message.addEventListener('keypress', e => {
if (e.charCode !== 13) return;
ws.send(message.value);
message.value = '';
});
})();
</script>
</body>
</html>
إعادة تشغيل الخادم
الآن أعد تشغيل الخادم وقم بزيارة صفحة الويب باتباع الإرشادات السابقة. إذا قمت بإيقاف awps-tunnel
، يرجى أيضا إعادة تشغيل أداة النفق.
الخطوات التالية
يوفر لك هذا البرنامج التعليمي فكرة أساسية عن كيفية عمل نظام الأحداث في خدمة Azure Web PubSub.
اطلع على البرامج التعليمة الأخرى للحصول على نظرة شاملة حول كيفية استخدام الخدمة.