快速入门:使用 JavaScript 通过 Azure Functions 和 SignalR 服务创建无服务器应用
在本文中,你将使用 Azure SignalR 服务、Azure Functions 和 JavaScript 生成一个无服务器应用程序,以便向客户端广播消息。
先决条件
本快速入门可以在 macOS、Windows 或 Linux 上运行。
先决条件 | 说明 |
---|---|
Azure 订阅 | 如果你没有订阅,请创建一个 Azure 试用帐户 |
代码编辑器 | 需要一个代码编辑器,例如 Visual Studio Code。 |
Azure Functions Core Tools | 需要版本 4.0.5611 或更高版本才能运行 v4 编程模型Node.js。 |
Node.js LTS | 请参阅 Azure Functions JavaScript 开发人员指南中支持的 node.js 版本。 |
Azurite | SignalR 绑定需要 Azure 存储。 在本地运行函数时,可以使用本地存储仿真器。 |
Azure CLI | (可选)可以使用 Azure CLI 创建 Azure SignalR 服务实例。 |
创建 Azure SignalR 服务实例
在本部分中,你将创建一个基本 Azure SignalR 实例来用于你的应用。 以下步骤使用 Azure 门户创建新实例,但你也可以使用 Azure CLI。 有关详细信息,请参阅 Azure SignalR 服务 CLI 参考中的 az signalr create 命令。
- 登录 Azure 门户。
- 在页面的左上角,选择“+ 创建资源” 。
- 在“创建资源”页上,在“搜索服务和市场”文本框中,输入“signalr”,然后从列表中选择“SignalR 服务”。
- 在“SignalR 服务”页上,选择“创建”。
- 在“基本信息”选项卡上,输入新 SignalR 服务实例的基本信息。 输入以下值:
字段 | 建议的值 | 描述 |
---|---|---|
订阅 | 选择订阅 | 选择要用于创建新的 SignalR 服务实例的订阅。 |
资源组 | 创建一个名为 SignalRTestResources 的资源组 | 为 SignalR 资源选择或创建资源组。 对于本教程,创建新的资源组比使用现有资源组更为合适。 若要在完成本教程后释放资源,请删除资源组。 删除资源组还会删除属于该组的所有资源。 此操作不能撤消。 删除资源组之前,请确保它不包含你希望保留的资源。 有关详细信息,请参阅 Using resource groups to manage your Azure resources(使用资源组管理 Azure 资源)。 |
资源名称 | testsignalr | 输入用于 SignalR 资源的唯一资源名称。 如果你的区域中已使用了 testsignalr,请添加一个数字或字符,以将名称设为唯一。 该名称必须是包含 1 到 63 个字符的字符串,只能包含数字、字母和连字符 ( - ) 字符。 该名称的开头或末尾不能是连字符字符,并且连续的连字符字符无效。 |
区域 | 选择你的区域 | 为新的 SignalR 服务实例选择合适的区域。 Azure SignalR 服务当前并非在所有区域中都可用。 有关详细信息,请参阅 Azure SignalR 服务区域可用性。 |
定价层 | 选择“更改”,然后选择“免费(仅限开发/测试)”。 选择“选择”以确认你选择的定价层。 | Azure SignalR 服务有三个定价层:免费、标准和高级。 教程使用的是免费层,除非在先决条件中另行说明。 若要详细了解各个层级之间的功能差异以及定价,请参阅 Azure SignalR 服务定价 |
服务模式 | 选择适当的服务模式 | 在 Web 应用中托管 SignalR 中心逻辑并使用 SignalR 服务作为代理时,请使用“默认”。 使用无服务器技术(如 Azure Functions)托管 SignalR 中心逻辑时,请使用“无服务器”。 “经典”模式仅用于向后兼容,不建议使用。 有关详细信息,请参阅 Azure SignalR 服务中的服务模式。 |
对于 SignalR 教程,你不需要更改“网络”和“标记”选项卡上的设置。
- 选择“基本信息”选项卡底部的“查看 + 创建”按钮。
- 在“查看 + 创建”选项卡上检查各个值,然后选择“创建”。 部署需要几分钟时间才能完成。
- 在部署完成后,选择“转到资源组”按钮。
- 在 SignalR 资源页面上,从左侧菜单中选择“设置”下的“密钥”。
- 复制主密钥的连接字符串。 在本教程中,稍后你将需要使用此连接字符串来配置你的应用。
设置函数项目
确保已安装 Azure Functions Core Tools。
- 打开命令行。
- 创建项目目录,然后将其更改为该项目目录。
- 运行 Azure Functions
func init
命令以初始化新项目。
func init --worker-runtime javascript --language javascript --model V4
创建项目函数
初始化项目后,需要创建函数。 此项目需要三个函数:
index
:托管客户端的网页。negotiate
:允许客户端获取访问令牌。broadcast
:使用时间触发器定期将消息广播到所有客户端。
从项目的根目录运行 func new
命令时,Azure Functions Core Tools 会创建函数源文件,并将其存储在以函数名称命名的文件夹中。 根据需要编辑文件,将默认代码替换为应用代码。
创建索引函数
运行以下命令来创建
index
函数。func new -n index -t HttpTrigger
编辑 src/functions/httpTrigger.js,并将内容替换为以下 json 代码:
const { app } = require('@azure/functions'); const fs = require('fs').promises; const path = require('path'); app.http('index', { methods: ['GET', 'POST'], authLevel: 'anonymous', handler: async (request, context) => { try { context.log(`Http function processed request for url "${request.url}"`); const filePath = path.join(__dirname,'../content/index.html'); const html = await fs.readFile(filePath); return { body: html, headers: { 'Content-Type': 'text/html' } }; } catch (error) { context.log(error); return { status: 500, jsonBody: error } } } });
创建协商函数
运行以下命令来创建
negotiate
函数。func new -n negotiate -t HttpTrigger
编辑 src/functions/negotiate.js,并将内容替换为以下 json 代码:
const { app, input } = require('@azure/functions'); const inputSignalR = input.generic({ type: 'signalRConnectionInfo', name: 'connectionInfo', hubName: 'serverless', connectionStringSetting: 'SIGNALR_CONNECTION_STRING', }); app.post('negotiate', { authLevel: 'anonymous', handler: (request, context) => { try { return { body: JSON.stringify(context.extraInputs.get(inputSignalR)) } } catch (error) { context.log(error); return { status: 500, jsonBody: error } } }, route: 'negotiate', extraInputs: [inputSignalR], });
创建广播函数。
运行以下命令来创建
broadcast
函数。func new -n broadcast -t TimerTrigger
编辑 src/functions/broadcast.js,并将内容替换为以下代码:
const { app, output } = require('@azure/functions'); const getStars = require('../getStars'); var etag = ''; var star = 0; const goingOutToSignalR = output.generic({ type: 'signalR', name: 'signalR', hubName: 'serverless', connectionStringSetting: 'SIGNALR_CONNECTION_STRING', }); app.timer('sendMessasge', { schedule: '0 * * * * *', extraOutputs: [goingOutToSignalR], handler: async (myTimer, context) => { try { const response = await getStars(etag); if(response.etag === etag){ console.log(`Same etag: ${response.etag}, no need to broadcast message`); return; } etag = response.etag; const message = `${response.stars}`; context.extraOutputs.set(goingOutToSignalR, { 'target': 'newMessage', 'arguments': [message] }); } catch (error) { context.log(error); } } });
创建 index.html 文件
本应用的客户端界面是网页。 index
函数从 content/index.html 文件中读取 HTML 内容。
在项目根文件夹中创建名为
content
的文件夹。创建 content/index.html 文件。
将以下内容复制到 content/index.html 文件并保存它:
<html> <body> <h1>Azure SignalR Serverless Sample</h1> <div>Instructions: Goto <a href="https://github.com/Azure/azure-signalr">GitHub repo</a> and star the repository.</div> <hr> <div>Star count: <div id="messages"></div></div> <script src="https://cdnjs.cloudflare.com/ajax/libs/microsoft-signalr/8.0.0/signalr.min.js"></script> <script> let messages = document.querySelector('#messages'); const apiBaseUrl = window.location.origin; console.log(`apiBaseUrl: ${apiBaseUrl}`); const connection = new signalR.HubConnectionBuilder() .withUrl(apiBaseUrl + '/api') .configureLogging(signalR.LogLevel.Information) .build(); connection.on('newMessage', (message) => { console.log(`message: ${message}`); document.getElementById("messages").innerHTML = message; }); connection.start() .catch(console.error); </script> </body> </html>
设置 Azure 存储
Azure Functions 需要一个存储帐户才能工作。 选择以下两个选项之一:
- 运行免费的 Azure 存储模拟器。
- 使用 Azure 存储服务。 如果继续使用它,可能会产生费用。
启动 Azurite 存储模拟器:
azurite -l azurite -d azurite\debug.log
确保 local.settings.json 中的
AzureWebJobsStorage
设置为UseDevelopmentStorage=true
。
将 SignalR 服务连接字符串添加到函数应用设置
操作即将完成。 最后一步是在 Azure 函数应用设置中设置 SignalR 服务连接字符串。
在 Azure 门户中,转到之前部署的 SignalR 实例。
选择“密钥”以查看 SignalR 服务实例的连接字符串。
复制主连接字符串并执行命令:
func settings add AzureSignalRConnectionString "<signalr-connection-string>"
在本地运行 Azure 函数应用
在本地环境中运行 Azure 函数应用:
func start
在本地运行 Azure 函数后,转到 http://localhost:7071/api/index
。 该页会显示 GitHub Azure/azure-signalr 存储库的当前星级数。 在 GitHub 中为存储库设置星级或取消设置星级时,将会每隔几秒看到刷新的计数。
遇到问题? 请试用故障排除指南。
清理资源
如果不打算继续使用此应用,请按照以下步骤删除本快速入门中创建的所有资源,以免产生任何费用:
在 Azure 门户的最左侧选择“资源组”,,然后选择创建的资源组。 或者,可以使用搜索框按名称查找资源组。
在打开的窗口中选择资源组,然后单击“删除资源组”。
在新窗口中键入要删除的资源组的名称,然后单击“删除”。
示例代码
可以从 GitHub 存储库获取本文中使用的所有代码:
后续步骤
在本快速入门中,你在 localhost 中生成并运行了一个实时无服务器应用程序。 接着,详细了解了如何通过 SignalR 服务在客户端与 Azure Functions 之间进行双向通信。