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

{
"behaviors": [
{ // 声明交互类型是卡片回传交互。
"type": "callback",
"value": {
// 回传交互数据。开放平台 SDK 仅支持对象类型的卡片回传参数。
"key": "value"
}
}
]
}
package main
import (
"context"
"fmt"
larkcore "github.com/larksuite/oapi-sdk-go/v3/core"
"github.com/larksuite/oapi-sdk-go/v3/event/dispatcher"
"github.com/larksuite/oapi-sdk-go/v3/event/dispatcher/callback"
larkws "github.com/larksuite/oapi-sdk-go/v3/ws"
)
func main() {
// 注册回调
eventHandler := dispatcher.NewEventDispatcher("", "").
// 监听「卡片回传交互 card.action.trigger」
OnP2CardActionTrigger(func(ctx context.Context, event *callback.CardActionTriggerEvent) (*callback.CardActionTriggerResponse, error) {
fmt.Printf("[ OnP2CardActionTrigger access ], data: %s\n", larkcore.Prettify(event))
return nil, nil
}).
// 监听「拉取链接预览数据 url.preview.get」
OnP2CardURLPreviewGet(func(ctx context.Context, event *callback.URLPreviewGetEvent) (*callback.URLPreviewGetResponse, error) {
fmt.Printf("[ OnP2URLPreviewAction access ], data: %s\n", larkcore.Prettify(event))
return nil, 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)
}
}
connected to wss://xxxxx,主线程将阻塞,直到进程结束。


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/event/dispatcher/callback"
)
func main() {
handler := dispatcher.NewEventDispatcher("verificationToken", "eventEncryptKey")
handler.OnP2CardActionTrigger(func(ctx context.Context, event *callback.CardActionTriggerEvent) (*callback.CardActionTriggerResponse, error) {
fmt.Println("receive card action")
fmt.Println(larkcore.Prettify(event))
return nil, nil
}).OnP2CardURLPreviewGet(func(ctx context.Context, event *callback.URLPreviewGetEvent) (*callback.URLPreviewGetResponse, error) {
fmt.Println(event)
return nil, nil
})
// 注册 http 路由
http.HandleFunc("/webhook/event", httpserverext.NewEventHandlerFunc(handler,
larkevent.WithLogLevel(larkcore.LogLevelDebug)))
// 启动服务
err := http.ListenAndServe(":7777", nil)
if err != nil {
panic(err)
}
}
import (
"context"
"fmt"
"net/http"
"github.com/larksuite/oapi-sdk-go/v3/card"
"github.com/larksuite/oapi-sdk-go/v3/core"
"github.com/larksuite/oapi-sdk-go/v3/core/httpserverext"
)
func main() {
// 创建卡片处理器
cardHandler := larkcard.NewCardActionHandler("verificationToken", "eventEncryptKey", func(ctx context.Context, cardAction *larkcard.CardAction) (interface{}, error) {
// 处理卡片行为, 这里简单打印卡片内容
fmt.Println(larkcore.Prettify(cardAction))
fmt.Println(cardAction.RequestId())
// 无返回值示例
return nil, nil
})
// 注册处理器
http.HandleFunc("/webhook/card", httpserverext.NewCardActionHandlerFunc(cardHandler, larkevent.WithLogLevel(larkcore.LogLevelDebug)))
// 启动 http 服务
err := http.ListenAndServe(":9999", nil)
if err != nil {
panic(err)
}
}go get -u github.com/larksuite/oapi-sdk-ginimport (
"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"
)
func main() {
// 创建卡片处理器
cardHandler := larkcard.NewCardActionHandler("v", "", func(ctx context.Context, cardAction *larkcard.CardAction) (interface{}, error) {
fmt.Println(larkcore.Prettify(cardAction))
fmt.Println(cardAction.RequestId())
return nil, nil
})
...
// 在已有的 Gin 实例上注册卡片处理路由
gin.POST("/webhook/card", sdkginext.NewCardActionHandlerFunc(cardHandler))
...
}import (
"context"
"fmt"
"net/http"
"github.com/larksuite/oapi-sdk-go/v3/card"
"github.com/larksuite/oapi-sdk-go/v3/core"
"github.com/larksuite/oapi-sdk-go/v3/core/httpserverext"
)
func main() {
// 创建卡片处理器
cardHandler := larkcard.NewCardActionHandler("v", "", func(ctx context.Context, cardAction *larkcard.CardAction) (interface{}, error) {
fmt.Println(larkcore.Prettify(cardAction))
fmt.Println(cardAction.RequestId())
// 创建卡片信息
messageCard := larkcard.NewMessageCard().
Config(config).
Header(header).
Elements([]larkcard.MessageCardElement{divElement, processPersonElement}).
CardLink(cardLink).
Build()
return messageCard, nil
})
// 注册处理器
http.HandleFunc("/webhook/card", httpserverext.NewCardActionHandlerFunc(cardHandler, larkevent.WithLogLevel(larkcore.LogLevelDebug)))
// 启动 http 服务
err := http.ListenAndServe(":9999", nil)
if err != nil {
panic(err)
}
}import (
"context"
"fmt"
"net/http"
"github.com/larksuite/oapi-sdk-go/v3/card"
"github.com/larksuite/oapi-sdk-go/v3/core"
"github.com/larksuite/oapi-sdk-go/v3/core/httpserverext"
)
func main() {
// 创建卡片处理器
cardHandler := larkcard.NewCardActionHandler("v", "", func(ctx context.Context, cardAction *larkcard.CardAction) (interface{}, error) {
fmt.Println(larkcore.Prettify(cardAction))
fmt.Println(cardAction.RequestId())
// 创建 http body
body := make(map[string]interface{})
body["content"] = "hello"
i18n := make(map[string]string)
i18n["zh_cn"] = "你好"
i18n["en_us"] = "hello"
i18n["ja_jp"] = "こんにちは"
body["i18n"] = i18n
// 创建自定义消息:http状态码,body内容
resp := &larkcard.CustomResp{
StatusCode: 400,
Body: body,
}
return resp, nil
})
// 注册处理器
http.HandleFunc("/webhook/card", httpserverext.NewCardActionHandlerFunc(cardHandler, larkevent.WithLogLevel(larkcore.LogLevelDebug)))
// 启动 http 服务
err := http.ListenAndServe(":9999", nil)
if err != nil {
panic(err)
}
}import (
"context"
"fmt"
"net/http"
"github.com/larksuite/oapi-sdk-go/v3/card"
"github.com/larksuite/oapi-sdk-go/v3/core"
"github.com/larksuite/oapi-sdk-go/v3/core/httpserverext"
)
func main() {
// 创建卡片处理器
cardHandler := larkcard.NewCardActionHandler("v", "", func(ctx context.Context, cardAction *larkcard.CardAction) (interface{}, error) {
// 处理卡片行为, 这里简单打印卡片内容
fmt.Println(larkcore.Prettify(cardAction))
fmt.Println(cardAction.RequestId())
// 获取企业或组织 key 并发送消息
tenanKey := cardAction.TenantKey
// ISV 给指定企业或组织中的用户发送消息
resp, err := client.Im.Message.Create(context.Background(), larkim.NewCreateMessageReqBuilder().
ReceiveIdType(larkim.ReceiveIdTypeOpenId).
Body(larkim.NewCreateMessageReqBodyBuilder().
MsgType(larkim.MsgTypePost).
ReceiveId("ou_c245b0a7dff2725cfa2fb104f8b48b9d").
Content("text").
Build(), larkcore.WithTenantKey(tenanKey)).
Build())
// 发送结果处理,resp,err
return nil, nil
})
// 注册处理器
http.HandleFunc("/webhook/card", httpserverext.NewCardActionHandlerFunc(cardHandler, larkevent.WithLogLevel(larkcore.LogLevelDebug)))
// 启动 http 服务
err := http.ListenAndServe(":9999", nil)
if err != nil {
panic(err)
}
}