快速入门:使用 Javascript 通过 Azure Functions 和 SignalR 服务创建无服务器应用
在本文中,你将使用 Azure SignalR 服务、Azure Functions 和 JavaScript 生成一个无服务器应用程序,以便向客户端广播消息。
注意
可以从 GitHub 获取本文中使用的所有代码。
先决条件
本快速入门可以在 macOS、Windows 或 Linux 上运行。
先决条件 | 说明 |
---|---|
Azure 订阅 | 如果你没有订阅,请创建一个 Azure 试用帐户 |
代码编辑器 | 你需要一个代码编辑器,如 Visual Studio Code。 |
Azure Functions Core Tools | 需要版本 2.7.1505 或更高版本才能在本地运行 Python Azure 函数应用。 |
Node.js | 请参阅 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
命令以初始化新项目。
# Initialize a function project
func init --worker-runtime javascript
创建项目函数
初始化项目后,需要创建函数。 此项目需要三个函数:
index
:托管客户端的网页。negotiate
:允许客户端获取访问令牌。broadcast
:使用时间触发器定期将消息广播到所有客户端。
从项目的根目录运行 func new
命令时,Azure Functions Core Tools 会创建函数源文件,并将其存储在以函数名称命名的文件夹中。 根据需要编辑文件,将默认代码替换为应用代码。
创建索引函数
运行以下命令来创建
index
函数。func new -n index -t HttpTrigger
编辑 index/function.json,并将内容替换为以下 json 代码:
{ "bindings": [ { "authLevel": "anonymous", "type": "httpTrigger", "direction": "in", "name": "req", "methods": [ "get", "post" ] }, { "type": "http", "direction": "out", "name": "res" } ] }
编辑 index/index.js 并将内容替换为以下代码:
var fs = require('fs').promises module.exports = async function (context, req) { const path = context.executionContext.functionDirectory + '/../content/index.html' try { var data = await fs.readFile(path); context.res = { headers: { 'Content-Type': 'text/html' }, body: data } context.done() } catch (err) { context.log.error(err); context.done(err); } }
创建协商函数
运行以下命令来创建
negotiate
函数。func new -n negotiate -t HttpTrigger
编辑 negotiate/function.json,并将内容替换为以下 json 代码:
{ "disabled": false, "bindings": [ { "authLevel": "anonymous", "type": "httpTrigger", "direction": "in", "methods": [ "post" ], "name": "req", "route": "negotiate" }, { "type": "http", "direction": "out", "name": "res" }, { "type": "signalRConnectionInfo", "name": "connectionInfo", "hubName": "serverless", "connectionStringSetting": "AzureSignalRConnectionString", "direction": "in" } ] }
编辑 negotiate/index.js 并将内容替换为以下 JavaScript 代码:
module.exports = async function (context, req, connectionInfo) { context.res.body = connectionInfo; };
创建广播函数。
运行以下命令来创建
broadcast
函数。func new -n broadcast -t TimerTrigger
编辑 broadcast/function.json,并将内容替换为以下代码:
{ "bindings": [ { "name": "myTimer", "type": "timerTrigger", "direction": "in", "schedule": "*/5 * * * * *" }, { "type": "signalR", "name": "signalRMessages", "hubName": "serverless", "connectionStringSetting": "AzureSignalRConnectionString", "direction": "out" } ] }
编辑 broadcast/index.js,并将内容替换为以下代码:
var https = require('https'); var etag = ''; var star = 0; module.exports = function (context) { var req = https.request("https://api.github.com/repos/azure/azure-signalr", { method: 'GET', headers: {'User-Agent': 'serverless', 'If-None-Match': etag} }, res => { if (res.headers['etag']) { etag = res.headers['etag'] } var body = ""; res.on('data', data => { body += data; }); res.on("end", () => { if (res.statusCode === 200) { var jbody = JSON.parse(body); star = jbody['stargazers_count']; } context.bindings.signalRMessages = [{ "target": "newMessage", "arguments": [ `Current star count of https://github.com/Azure/azure-signalr is: ${star}` ] }] context.done(); }); }).on("error", (error) => { context.log(error); context.res = { status: 500, body: error }; context.done(); }); req.end(); }
创建 index.html 文件
本应用的客户端界面是网页。 index
函数从 content/index.html 文件中读取 HTML 内容。
在项目根文件夹中创建名为
content
的文件夹。创建 content/index.html 文件。
将以下内容复制到 content/index.html 文件并保存它:
<html> <body> <h1>Azure SignalR Serverless Sample</h1> <div id="messages"></div> <script src="https://cdnjs.cloudflare.com/ajax/libs/microsoft-signalr/3.1.7/signalr.min.js"></script> <script> let messages = document.querySelector('#messages'); const apiBaseUrl = window.location.origin; const connection = new signalR.HubConnectionBuilder() .withUrl(apiBaseUrl + '/api') .configureLogging(signalR.LogLevel.Information) .build(); connection.on('newMessage', (message) => { document.getElementById("messages").innerHTML = message; }); connection.start() .catch(console.error); </script> </body> </html>
将 SignalR 服务连接字符串添加到函数应用设置
Azure Functions 需要一个存储帐户才能工作。 可以安装并运行 Azurite 存储模拟器。 或者,可以使用以下命令更新设置以使用实际存储帐户:bash func settings add AzureWebJobsStorage "<storage-connection-string>"
操作即将完成。 最后一步是在 Azure 函数应用设置中设置 SignalR 服务连接字符串。
在 Azure 门户中,转到之前部署的 SignalR 实例。
选择“密钥”以查看 SignalR 服务实例的连接字符串。
复制主连接字符串并执行命令:
func settings add AzureSignalRConnectionString "<signalr-connection-string>"
在本地运行 Azure 函数应用
启动 Azurite 存储模拟器:
azurite
在本地环境中运行 Azure 函数应用:
func start
注意
如果在 Blob 存储上看到一个错误显示读取错误,请确保将 local.settings.json 文件中的“AzureWebJobsStorage”设置设为 UseDevelopmentStorage=true
。
在本地运行 Azure 函数后,转到 http://localhost:7071/api/index
。 该页会显示 GitHub Azure/azure-signalr 存储库的当前星级数。 在 GitHub 中为存储库设置星级或取消设置星级时,将会每隔几秒看到刷新的计数。
遇到问题? 请试用故障排除指南。
清理资源
如果不打算继续使用此应用,请按照以下步骤删除本快速入门中创建的所有资源,以免产生任何费用:
在 Azure 门户的最左侧选择“资源组”,,然后选择创建的资源组。 或者,可以使用搜索框按名称查找资源组。
在打开的窗口中选择资源组,然后单击“删除资源组”。
在新窗口中键入要删除的资源组的名称,然后单击“删除”。
后续步骤
在本快速入门中,你在 localhost 中生成并运行了一个实时无服务器应用程序。 接着,详细了解了如何通过 SignalR 服务在客户端与 Azure Functions 之间进行双向通信。