You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Azure Functions+WebPubSub:如何获取群组内客户端连接数?

解决方案:判断Azure WebPubSub群组内唯一连接用户

要实现消息发送时判断自身是否为群组唯一在线用户,核心是维护全局共享的群组连接计数——因为Azure WebPubSub的单连接状态是私有,无法跨连接共享。以下是三种可行方案,按推荐优先级排序:

方案一:使用Azure WebPubSub服务端全局状态(无需额外服务)

利用WebPubSub内置的服务端全局状态功能,通过原子操作维护群组在线计数,避免并发冲突。

步骤1:安装WebPubSub管理SDK

在Azure Function项目根目录执行:

npm install @azure/web-pubsub

步骤2:在connected事件中递增计数

修改connected/index.js,用户加入群组后原子递增计数:

const { WebPubSubServiceClient } = require("@azure/web-pubsub");

module.exports = async function (context, req) {
    // 将用户加入group1
    context.bindings.actions.push({
        actionName: "addUserToGroup",
        userId: context.bindingData.connectionContext.userId,
        group: "group1"
    });

    // 初始化服务端管理客户端
    const serviceClient = new WebPubSubServiceClient(
        process.env.WebPubSubConnectionString,
        "chat" // 替换为你的hub名称
    );

    // 原子递增群组在线计数(不存在则初始化为1)
    await serviceClient.setState("group1_online_count", {
        value: 1,
        operation: "increment"
    });

    context.res = { status: 200 };
};

步骤3:在disconnect事件中递减计数

修改disconnect/index.js,用户断开后原子递减计数:

const { WebPubSubServiceClient } = require("@azure/web-pubsub");

module.exports = async function (context, req) {
    const serviceClient = new WebPubSubServiceClient(
        process.env.WebPubSubConnectionString,
        "chat"
    );

    // 原子递减群组在线计数
    await serviceClient.setState("group1_online_count", {
        value: 1,
        operation: "decrement"
    });

    context.res = { status: 200 };
};

步骤4:在message事件中判断是否为唯一用户

修改message/index.js,获取计数并判断:

const { WebPubSubServiceClient } = require("@azure/web-pubsub");

module.exports = async function (context, req) {
    const serviceClient = new WebPubSubServiceClient(
        process.env.WebPubSubConnectionString,
        "chat"
    );

    // 获取群组在线计数
    const stateRes = await serviceClient.getState("group1_online_count");
    const onlineCount = parseInt(stateRes.value) || 0;
    const isOnlyUser = onlineCount === 1;

    // 处理消息并返回结果给群组
    const response = {
        actionName: "sendToGroup",
        group: "group1",
        data: JSON.stringify({
            content: req.body.data,
            isOnlyUser: isOnlyUser // 将判断结果传给客户端
        }),
        dataType: "json"
    };

    return response;
};

配置注意事项

在Azure Function App的应用设置中添加WebPubSubConnectionString,值为你的WebPubSub服务的连接字符串(可在Azure Portal的WebPubSub资源中获取)。

方案二:使用Azure Redis Cache(适合高并发/多群组场景)

如果你的应用涉及多个群组或高并发连接,用Redis维护计数性能更优。

步骤1:安装Redis客户端

npm install redis

步骤2:修改connected事件

const { createClient } = require('redis');

module.exports = async function (context, req) {
    context.bindings.actions.push({
        actionName: "addUserToGroup",
        userId: context.bindingData.connectionContext.userId,
        group: "group1"
    });

    const redisClient = createClient({ url: process.env.RedisConnectionString });
    await redisClient.connect();
    await redisClient.incr('group1_online_count');
    await redisClient.disconnect();

    context.res = { status: 200 };
};

步骤3:修改disconnect事件

const { createClient } = require('redis');

module.exports = async function (context, req) {
    const redisClient = createClient({ url: process.env.RedisConnectionString });
    await redisClient.connect();
    await redisClient.decr('group1_online_count');
    await redisClient.disconnect();

    context.res = { status: 200 };
};

步骤4:修改message事件

const { createClient } = require('redis');

module.exports = async function (context, req) {
    const redisClient = createClient({ url: process.env.RedisConnectionString });
    await redisClient.connect();
    const onlineCount = parseInt(await redisClient.get('group1_online_count')) || 0;
    const isOnlyUser = onlineCount === 1;
    await redisClient.disconnect();

    const response = {
        actionName: "sendToGroup",
        group: "group1",
        data: JSON.stringify({
            content: req.body.data,
            isOnlyUser: isOnlyUser
        }),
        dataType: "json"
    };

    return response;
};

方案三:调用WebPubSub群组连接列表API(适合小群组)

直接调用管理API获取群组内所有连接,通过列表长度判断在线数,适合用户量少的场景(大群组会有性能开销)。

修改message/index.js:

const { WebPubSubServiceClient } = require("@azure/web-pubsub");

module.exports = async function (context, req) {
    const serviceClient = new WebPubSubServiceClient(
        process.env.WebPubSubConnectionString,
        "chat"
    );

    // 获取群组内所有连接
    const connections = [];
    for await (const conn of serviceClient.listGroupConnections("group1")) {
        connections.push(conn);
    }
    const isOnlyUser = connections.length === 1;

    // 消息处理逻辑...
    const response = {
        actionName: "sendToGroup",
        group: "group1",
        data: JSON.stringify({
            content: req.body.data,
            isOnlyUser: isOnlyUser
        }),
        dataType: "json"
    };

    return response;
};

额外注意事项

  • 异常断开处理:若客户端异常断开(如网络中断),disconnect事件可能延迟触发,可设置WebPubSub的连接超时时间,或定期清理过期计数(Redis可设置键的过期时间,WebPubSub状态可添加TTL)。
  • 权限控制:确保Function App的身份有调用WebPubSub管理API的权限(使用连接字符串时默认具备权限)。

内容的提问来源于stack exchange,提问作者gabrielsalvador

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 01:57:38