| 订阅方式 | 介绍 |
|---|---|
| 使用长连接接收事件 | 该方式是飞书 SDK 内提供的能力,你可以通过集成飞书 SDK 与开放平台建立一条 WebSocket 全双工通道(你的服务器需要能够访问公网)。后续当应用订阅的事件发生时,开放平台会通过该通道向你的服务器发送消息。相较 于传统的 Webhook 模式,长连接模式大大降低了接入成本,将原先 1 周左右的开发周期降低到 5 分钟。具体优势如下:测试阶段无需使用内网穿透工具,通过长连接模式在本地开发环境中即可接收事件回调。SDK 内封装了鉴权逻辑,只在建连时进行鉴权,后续事件推送均为明文数据,无需再处理解密和验签逻辑。只需保证运行环境具备访问公网能力即可,无需提供公网 IP 或域名。无需部署防火墙和配置白名单。 |
| 将事件发送至开发者服务器 | 传统的 Webhook 模式,该方式需要你提供用于接收事件消息的服务器公网地址。后续当应用订阅的事件发生时,开放平台会向服务器的公网地址发送 HTTP POST 请求,请求内包含事件数据。 |

package main
import (
"context"
"fmt"
larkcore "github.com/larksuite/oapi-sdk-go/v3/core"
larkevent "github.com/larksuite/oapi-sdk-go/v3/event"
"github.com/larksuite/oapi-sdk-go/v3/event/dispatcher"
larkim "github.com/larksuite/oapi-sdk-go/v3/service/im/v1"
larkws "github.com/larksuite/oapi-sdk-go/v3/ws"
)
func main() {
// 注册事件回调,OnP2MessageReceiveV1 为接收消息 v2.0;OnCustomizedEvent 内的 message 为接收消息 v1.0。
eventHandler := dispatcher.NewEventDispatcher("", "").
OnP2MessageReceiveV1(func(ctx context.Context, event *larkim.P2MessageReceiveV1) error {
fmt.Printf("[ OnP2MessageReceiveV1 access ], data: %s\n", larkcore.Prettify(event))
return nil
}).
OnCustomizedEvent("这里填入你要自定义订阅的 event 的 key,例如 out_approval", func(ctx context.Context, event *larkevent.EventReq) error {
fmt.Printf("[ OnCustomizedEvent access ], type: message, data: %s\n", string(event.Body))
return nil
})
// 创建Client
cli := larkws.NewClient("YOUR_APP_ID", "YOUR_APP_SECRET",
larkws.WithEventHandler(eventHandler),
larkws.WithLogLevel(larkcore.LogLevelDebug),
)
// 启动客户端
err := cli.Start(context.Background())
if err != nil {
panic(err)
}
}
onP2MessageReceiveV1 注册接收消息事件回调时,P2便对应的是 v2.0 版本事件结构。



package main
import (
"context"
"fmt"
"net/http"
"github.com/larksuite/oapi-sdk-go/v3/core"
"github.com/larksuite/oapi-sdk-go/v3/core/httpserverext"
"github.com/larksuite/oapi-sdk-go/v3/event"
"github.com/larksuite/oapi-sdk-go/v3/event/dispatcher"
"github.com/larksuite/oapi-sdk-go/v3/service/im/v1"
)
func main() {
// 注册消息处理器
// 用于签名验证和消息解密,默认可以传递为空串。但如果你在开发者后台 > 事件与回调 > 加密策略中开启了加密,则必须传递 Encrypt Key 和 Verification Token
handler := dispatcher.NewEventDispatcher("verificationToken", "eventEncryptKey")
handler = handler.OnP2MessageReceiveV1(func(ctx context.Context, event *larkim.P2MessageReceiveV1) error {
// 处理消息 event,这里简单打印消息的内容
fmt.Println(larkcore.Prettify(event))
fmt.Println(event.RequestId())
return nil
}).OnCustomizedEvent("这里填入你要自定义订阅的 event 的 key,例如 out_approval", func(ctx context.Context, event *larkevent.EventReq) error {
// 原生消息体
fmt.Println(string(event.Body))
fmt.Println(larkcore.Prettify(event.Header))
fmt.Println(larkcore.Prettify(event.RequestURI))
fmt.Println(event.RequestId())
// 处理消息
cipherEventJsonStr, err := handler.ParseReq(ctx, event)
if err != nil {
// 错误处理
return err
}
plainEventJsonStr, err := handler.DecryptEvent(ctx, cipherEventJsonStr)
if err != nil {
// 错误处理
return err
}
// 处理解密后的 消息体
fmt.Println(plainEventJsonStr)
return nil
})
// 注册 http 路由
http.HandleFunc("/webhook/event", httpserverext.NewEventHandlerFunc(handler, larkevent.WithLogLevel(larkcore.LogLevelDebug)))
// 启动 http 服务
err := http.ListenAndServe(":9999", nil)
if err != nil {
panic(err)
}
}
import (
"context"
"fmt"
"github.com/gin-gonic/gin"
"github.com/larksuite/oapi-sdk-gin"
"github.com/larksuite/oapi-sdk-go/v3/card"
"github.com/larksuite/oapi-sdk-go/v3/core"
"github.com/larksuite/oapi-sdk-go/v3/event/dispatcher"
"github.com/larksuite/oapi-sdk-go/v3/service/contact/v3"
"github.com/larksuite/oapi-sdk-go/v3/service/im/v1"
)
func main() {
// 注册消息处理器
handler := dispatcher.NewEventDispatcher("verificationToken", "eventEncryptKey").OnP2MessageReceiveV1(func(ctx context.Context, event *larkim.P2MessageReceiveV1) error {
fmt.Println(larkcore.Prettify(event))
fmt.Println(event.RequestId())
return nil
}).OnP2MessageReadV1(func(ctx context.Context, event *larkim.P2MessageReadV1) error {
fmt.Println(larkcore.Prettify(event))
fmt.Println(event.RequestId())
return nil
}).OnP2UserCreatedV3(func(ctx context.Context, event *larkcontact.P2UserCreatedV3) error {
fmt.Println(larkcore.Prettify(event))
fmt.Println(event.RequestId())
return nil
})
...
// 在已有 Gin 实例上注册消息处理路由
gin.POST("/webhook/event", sdkginext.NewEventHandlerFunc(handler))
}import (
"context"
"fmt"
lark "github.com/larksuite/oapi-sdk-go/v3"
"net/http"
"os"
"github.com/larksuite/oapi-sdk-go/v3/core"
"github.com/larksuite/oapi-sdk-go/v3/core/httpserverext"
"github.com/larksuite/oapi-sdk-go/v3/event"
"github.com/larksuite/oapi-sdk-go/v3/event/dispatcher"
"github.com/larksuite/oapi-sdk-go/v3/service/im/v1"
)
func main() {
// 创建 API Client。你需在此传入你的应用的实际 App ID 和 App Secret
var appID, appSecret = os.Getenv("APP_ID"), os.Getenv("APP_SECRET")
var cli = lark.NewClient(appID, appSecret, lark.WithLogReqAtDebug(true), lark.WithLogLevel(larkcore.LogLevelDebug))
// 注册消息处理器
handler := dispatcher.NewEventDispatcher("verificationToken", "eventEncryptKey").OnP2MessageReceiveV1(func(ctx context.Context, event *larkim.P2MessageReceiveV1) error {
// 处理消息 event,这里简单打印消息的内容
fmt.Println(larkcore.Prettify(event))
fmt.Println(event.RequestId())
// 获取企业或组织 key 并发送消息
tenantKey := event.TenantKey()
// 商店应用给指定企业或组织的用户发送消息
resp, err := cli.Im.Message.Create(context.Background(), larkim.NewCreateMessageReqBuilder().
ReceiveIdType(larkim.ReceiveIdTypeOpenId).
Body(larkim.NewCreateMessageReqBodyBuilder().
MsgType(larkim.MsgTypePost).
ReceiveId("ou_c245b0a7dff2725cfa2fb104f8babcef").
Content("text").
Build()).
Build(), larkcore.WithTenantKey(tenantKey))
// 发送结果处理,resp,err
fmt.Println(resp, err)
return nil
})
// 注册 http 路由
http.HandleFunc("/webhook/event", httpserverext.NewEventHandlerFunc(handler, larkevent.WithLogLevel(larkcore.LogLevelDebug)))
// 启动 http 服务
err := http.ListenAndServe(":9999", nil)
if err != nil {
panic(err)
}
}