使用 Azure SignalR 服务构建实时无服务器应用程序
今天,微软宣布Azure SignalR 服务绑定正式面向 Azure Functions 推出。这些绑定使 Azure Functions 能够与 SignalR 服务无缝集成,并通过 WebSocket 大规模广播实时消息。
我们将探讨如何使用 HTML 和 JavaScript 构建一个基于浏览器的协作绘图应用程序。多人可以在各自的浏览器中打开该应用程序,并在画布上进行绘制。所有更改都会使用 Azure Functions 和 SignalR 服务实时同步。
Azure Functions 近期也正式推出了对 Java 语言的支持。本文中,我们将使用 Java 编写函数,但 SignalR 服务绑定也适用于 Azure Functions 支持的其他语言。您可以访问GitHub 代码库查看Java、C# 和 JavaScript 的源代码。
概述
该应用程序由三个主要组件构成:绘图画布、Azure 函数应用程序和 Azure SignalR 服务。
-
Canvas 是一个简单的 JavaScript 应用,运行在浏览器中。应用启动时,它会从名为“negotiate”的 Azure 函数中检索 SignalR 服务连接终结点和访问令牌。
-
该应用连接到 SignalR 服务并建立实时通道。通常情况下,这是一个 WebSocket 连接,但如果 WebSocket 不可用,SignalR 会自动回退到其他传输方式。
-
当在画布上绘制线条时,该应用程序会将一系列笔画发送到名为“draw”的 Azure 函数。
-
绘图 Azure 函数使用 SignalR 服务将一系列笔画广播到所有已连接的客户端。
创建 Azure SignalR 服务实例
Azure SignalR 服务是一个完全托管的实时消息平台,我们的应用程序将使用它来广播消息。我们可以在 Azure 门户中创建一个免费的SignalR 服务实例,也可以运行以下 Azure CLI 命令。
az signalr create -n $SIGNALR_NAME -g $GROUP_NAME --sku Free_DS2 -l westus
实例创建完成后,我们需要获取函数应用将使用的连接字符串。
az signalr key list -n $SIGNALR_NAME -g $GROUP_NAME
构建 Azure 函数应用
Azure 函数应用包含两个关键函数。第一个negotiate函数返回 SignalR 服务连接信息。第二个函数draw会在任何画布上绘制线条时被调用;它会将这些线条广播到其他画布。
如果您之前没有使用过 Azure Functions,请查看他们的快速入门指南。
协商功能
此 HTTP 触发函数使用SignalRConnectionInfoInput绑定来生成客户端的访问令牌和端点信息。绑定使用连接字符串生成这些信息。
@FunctionName("negotiate")
public SignalRConnectionInfo negotiate(
@HttpTrigger(
name = "req",
methods = { HttpMethod.POST },
authLevel = AuthorizationLevel.ANONYMOUS) HttpRequestMessage<Optional<String>> req,
@SignalRConnectionInfoInput(
name = "connectionInfo",
hubName = "serverlessdraw") SignalRConnectionInfo connectionInfo) {
return connectionInfo;
}
绘制函数
HTTPdraw触发函数使用SignalROutput绑定将绘制在画布上的笔画广播到当前连接到 SignalR 服务的所有画布。
它只是将 HTTP 请求正文的内容转发给 SignalR 服务。
@FunctionName("draw")
public void draw(
@HttpTrigger(
name = "req",
methods = { HttpMethod.POST },
authLevel = AuthorizationLevel.ANONYMOUS) HttpRequestMessage<StrokeCollection> req,
@SignalROutput(
name = "signalRMessage",
hubName = "serverlessdraw") OutputBinding<SignalRMessage> signalRMessage) {
StrokeCollection strokeCollection = req.getBody();
SignalRMessage msg = new SignalRMessage("newStrokes", strokeCollection);
signalRMessage.setValue(msg);
}
创建绘图画布
Canvas 是一个出乎意料地简单的基于浏览器的 JavaScript 应用,它使用 HTML Canvas。你可以在我的 Twitch 直播中观看我构建它的第一个版本。
SignalR 服务连接
Canvas 应用启动后,我们首先要做的就是连接到 SignalR 服务。我们可以使用 CDN 来引用 SignalR JavaScript 客户端。
<script src="https://cdn.jsdelivr.net/npm/@aspnet/signalr@1.1.2/dist/browser/signalr.js"></script>
然后我们可以使用客户端创建与 SignalR 服务的连接。按照惯例,SignalR 客户端会/negotiate在 URL 末尾添加一个参数来发现连接协商端点,因此在初始化函数时,我们会将这部分从函数的 URL 中省略HubConnectionBuilder。
var connection = new signalR.HubConnectionBuilder()
.withUrl(`${apiBaseUrl}/api`) // function URL minus /negotiate
.build()
// set up event listeners
connection.on('newStrokes', drawStrokes)
connection.on('clearCanvas', clearCanvas)
connection.start()
.then(() => console.log('connected'))
在配置连接并启动连接的过程中,我们设置了几个事件监听器。当 SignalR 服务收到与这些名称匹配的事件时,就会调用相应的事件处理程序。以下是该clearCanvas函数的代码:
function clearCanvas() {
ctx.clearRect(0, 0, canvas.width, canvas.height)
}
绘画画布
主画布(正如你所料)就是一个单独的<canvas>标签:
<canvas id="draw-canvas" height="500" width="800"></canvas>
主要的 JavaScript 函数名为 ` mouseMovedrawStroke`。每次绘制笔画时都会调用它。我们确定线条的起点和终点,并将其绘制在画布上。然后,我们将笔画添加到数组中,以便将多个笔画收集起来并批量发送。
function mouseMove(ev) {
// 🌟 math happens here
drawStroke(start, end, colorButton.value)
unsentStrokes.push({
start: start,
end: end,
color: colorButton.value
})
}
我们大约每隔 250 毫秒将一批笔画发送到我们的drawAzure 函数。
setInterval(function () {
if (unsentStrokes.length) {
axios.post(`${apiBaseUrl}/api/draw`, {
sender: clientId,
strokes: unsentStrokes
})
unsentStrokes = []
}
}, 250)
绘制函数将使用 SignalR 服务newStrokes在应用程序的每个运行实例中触发事件。这将调用一个名为 draw 的函数drawStrokes来绘制笔画。
成品长这样:
请查看GitHub 仓库,获取 Java、JavaScript 和 C# 编写的函数应用程序的源代码。
资源
- Azure SignalR 服务绑定支持 Azure Functions 正式发布公告
- 宣布 Azure Functions 正式推出 Java 支持
- Azure Functions 绑定参考
- SignalR 服务无服务器编程指南
- 无服务器绘图源代码

