飞书自建应用开发笔记

飞书自建应用开发笔记

2025年11月15日 阅读:11 字数:770 阅读时长:2 分钟

最近在使用nodejs开发飞书自建应用,简单记录一下。

最近在使用nodejs开发飞书自建应用,简单记录一下。

可以借助飞书的SDK(@larksuiteoapi/node-sdk),提升开发效率。

事件订阅

事件订阅方式分为 使用长连接接收事件 和 将事件发送至开发者服务器 两种。

使用长连接接收事件

长连接是飞书 SDK 内提供的能力,你可以在本地服务器集成飞书 SDK, 与开放平台建立一条 WebSocket 全双工通道(你的服务器需要能够访问公网)。后续当应用订阅的事件发生时,开放平台会通过该通道向你的服务器发送事件消息。

创建长连接客户端:

import { WSClient } from '@larksuiteoapi/node-sdk';

public createWsClient() {
  // 初始化飞书SDK配置
  const config = {
    appId: 飞书应用ID,
    appSecret: 飞书应用秘钥,
  };

  const wsClient = new WSClient(config);

  return wsClient;
}

监听事件:

import { EventDispatcher } from '@larksuiteoapi/node-sdk';

const wsClient = createWsClient()

const eventDispatcher = new EventDispatcher({}).register({
  'corehr.job_data.employed_v1': async data => {
    console.log(data);
  },
});

// 建立长连接 Establish persistent connection
await wsClient.start({ eventDispatcher });

将事件发送至开发者服务器

自建一个服务器,通过 Webhook 模式接收飞书开放平台的事件订阅通知,需要提供服务器的公网访问地址。

import http from "http";
import * as lark from "@larksuiteoapi/node-sdk";

const eventDispatcher = new lark.EventDispatcher({
  encryptKey: "encrypt key", // 加密密钥
}).register({
  "im.message.receive_v1": async (data) => {
    const chatId = data.message.chat_id;
    const res = await client.im.message.create({
      params: {
        receive_id_type: "chat_id",
      },
      data: {
        receive_id: chatId,
        content: JSON.stringify({ text: "hello world" }),
        msg_type: "text",
      },
    });
    return res;
  },
});

const server = http.createServer();
server.on(
  "request",
  lark.adaptDefault("/webhook/event", eventDispatcher, {
    autoChallenge: true,
  })
);
server.listen(3000);

接口请求

创建http客户端:

import { Client } from '@larksuiteoapi/node-sdk';

public createClient() {
  // 初始化飞书SDK配置
    const config = {
      appId,
      appSecret,
    };

    const client = new Client(config);

    return client;
}

api调用

/**
 * 发送消息
 * @see https://open.feishu.cn/document/server-docs/im-v1/message/create
 */
public async sendMessage(params: {
  client: Client;
  /** 接收对象ID */
  receiveId: string;
  /** 内容 */
  content: string;
  /** 消息类型 */
  msgType?: string;
  /** 接收对象ID类型 */
  receiveIdType?: "open_id" | "user_id" | "union_id" | "email" | "chat_id";
}) {
  const {
    client,
    receiveId,
    content,
    msgType = "text",
    receiveIdType = "chat_id",
  } = params;
  try {
    const response = await this.ctx.helper.throttleRun(
      "im.v1.message.create",
      { intervalCap: 16, interval: 1000 },
      () =>
        client.im.v1.message.create({
          params: {
            receive_id_type: receiveIdType,
          },
          data: {
            receive_id: receiveId,
            msg_type: msgType,
            content,
          },
        })
    );

    if (response.code !== 0) {
      throw new Error(`发送消息失败: ${response.msg}`);
    }

    return response.data?.message_id;
  } catch (error) {
    this.logger.error(`发送消息错误: ${(error as Error).message}`);
    throw error;
  }
}

常见问题

频率限制

飞书的open api一般都有调用频率限制,简单的可以使用p-queue来限制请求频率,如上面调用Api所示,传入{ intervalCap: 16, interval: 1000 },限制每秒最多调用16次。

import PQueue from "p-queue";

const pool = new Map<string, PQueue>();

/**
 * 频控运行
 * @param key 队列唯一标识
 * @param queueOpts PQueue队列参数
 * @param factory promise函数
 */
export function throttleRun<T>(
  key: string,
  queueOpts: any,
  factory: () => Promise<T>
): Promise<T> {
  if (!pool.has(key)) {
    pool.set(
      key,
      new PQueue({
        ...queueOpts,
        timeout: 30000, // 队列任务超时时间
        // carryoverConcurrencyCount: true,
      })
    );
  }
  return pool.get(key)!.add(factory);
}

bot is invisible to user ids错误

调用Api的时候返回机器人无法访问用户ID的错误

{
  code: 232043,
  msg: "Your request contains unavailable ids, ext=bot is invisible to user ids: [ou_xxx ou_xxx]",
  error: [Object],
  log_id: "xxx",
  troubleshooter: "排查建议查看(Troubleshooting suggestions): https://open.feishu.cn/search?from=openapi&log_id=xxx&code=232043&method_id=6936075528890908700",
}

这是因为应用权限或数据权限缺少问题,在飞书开发者后台添加Api权限,或者在发布版本中更新应用可用范围。

推荐阅读

恰饭区

评论区 (0)

0/500

还没有评论,快来抢第一吧