快速集成
本页从零开始写一个能登录、收发消息的 Go 程序:创建工程、安装 SDK、创建客户端、用业务服务端签发的凭证登录、建立长连接、收消息并自动回复、优雅退出。完成后你会得到一个可以直接 go run 的单文件程序,可以在它的基础上写自己的机器人或集成逻辑。
准备工作
- 在控制台创建应用,在应用详情中记下 AppKey(如
1575529652#demo)和 IM 服务的地址(如https://im.example.com)。 - 业务服务端接入服务端 REST API,提供一个“获取 IM 登录凭证”的接口:程序以某个用户的身份调用它,业务服务端为这个用户签发登录凭证并返回,如
{"ticket": "ult_..."}。 - 安装 Go 1.26.5 或以上。
凭证 5 分钟内有效、只能使用一次,相当于用户的临时密码。App Token 和 Client Secret 只能保存在业务服务端,不能出现在 Go 程序中。开发和测试时,也可以用 curl 为测试账号签发一个凭证,复制到程序里用。
创建工程并安装
先下载客户端 SDK + Demo ZIP,完整解压。 在新的业务工程中执行,将 replace 的绝对路径改为实际解压位置:
mkdir imbot && cd imbot
go mod init example.com/imbot
go mod edit -require=github.com/deeprespond/im/sdk/go@v0.0.0
go mod edit -replace=github.com/deeprespond/im/sdk/go=/绝对路径/deeprespond-im-go-sdk-1.0.0-alpha/sdk/go保存下面的完整 main.go 后执行 go mod tidy。SDK 模块从本地源码加载;v0.0.0 是本地替换的占位版本。
使用本仓库源码
已有 IM 仓库时,把上面的替换路径改为 /绝对路径/im/sdk/go,其他代码和命令不变。 ZIP 保留了 sdk/go 布局,在压缩包或仓库内体验 Demo 都不需要创建 imbot,见 Demo 指南。
第 1 步:创建客户端
cli, err := im.New(im.Config{
AppKey: "1575529652#demo", // 组织#应用,在控制台的应用详情中查看
APIURL: "https://im.example.com", // IM 服务端 REST 地址
})
if err != nil {
panic(err)
}im.New 不做任何网络请求,只检查参数并填充缺省值。全部配置项见初始化、登录与连接。
第 2 步:登录
生产环境用业务服务端签发的凭证登录;开发测试时可以用密码登录作为捷径:
// 生产环境:ticket 来自你的业务服务端
session, err := cli.Login(ctx, im.LoginTicket, "alice", ticket)
// 开发测试捷径:密码登录(正式分发的程序不要这样写)
// session, err := cli.Login(ctx, im.LoginPassword, "alice", "pass-123")登录成功返回 *im.Session(访问令牌、续期令牌、会话 ID、本人资料)。令牌的保存与续期由 SDK 自动处理,你不需要刷新它。
第 3 步:订阅事件
长连接建立后,服务端的事件通过 OnEvent 回调交给你。收新消息只需处理 message.received:
cli.OnEvent(func(e im.Event) {
if e.Name != im.EventMessageReceived {
return
}
var m im.Message
if json.Unmarshal(e.Data, &m) != nil {
return
}
fmt.Printf("来自 %s:%s\n", m.Sender, m.TextBody())
})m.TextBody()提取文本消息的正文;其他类型的消息用m.BodyMap()拿到 body 对象;- 事件在同一个 goroutine 中按到达顺序分发,回调里的耗时操作会阻塞后续事件,需要慢处理时自己开 goroutine;
- 全部事件见事件与同步。
第 4 步:建立长连接并同步
if err := cli.ConnectWait(ctx); err != nil {
panic(err)
}ConnectWait 建立长连接并阻塞等待首次认证完成(内部最长等 15 秒)。连接建立后才能收到事件,断线后 SDK 自动重连。登录后建议做一次全量同步,把会话列表和最近消息拉进内存缓存:
n, err := cli.SyncAll(ctx)
fmt.Printf("已同步 %d 个会话\n", n)只收实时消息、不读历史的机器人可以跳过同步。
第 5 步:发送文本消息
msg, err := cli.SendText(ctx, im.ToUser("bob"), "你好", nil)
fmt.Println(msg.Seq, err)im.ToUser("bob") 发给某个用户,im.ToGroup("群 ID") 发给某个群。连接可用时消息优先走长连接,连接不可用时自动改走 REST;发送失败(返回错误)时是否重试由你决定。
第 6 步:优雅退出
<-ctx.Done() // 例如收到 Ctrl+C
_ = cli.Logout(context.Background()) // 退出登录:断开长连接并结束服务端会话只需断开连接、保持登录状态时,用 cli.Disconnect();之后可以再次 Connect。Go SDK 没有离线发送队列:SendText 返回成功即服务端已接收,之后投递由服务端完成;进程被直接杀死不影响已经发出的消息。
完整示例
把以下内容保存为 main.go。示例从环境变量读取凭证;实际程序中请改为调用你业务服务端的“获取 IM 登录凭证”接口。
package main
import (
"context"
"encoding/json"
"fmt"
"os"
"os/signal"
"syscall"
"time"
im "github.com/deeprespond/im/sdk/go"
)
// 向业务服务端获取当前用户的 IM 登录凭证。
// 实际程序中在这里调用你自己定义的接口;业务服务端校验身份后,
// 用 App Token 调 IM 服务的 REST API 为用户签发凭证并返回。
func fetchTicket() (string, error) {
t := os.Getenv("IM_TICKET")
if t == "" {
return "", fmt.Errorf("请先设置 IM_TICKET(由业务服务端签发,见文档“快速集成”)")
}
return t, nil
}
func main() {
// Ctrl+C 或 SIGTERM 时取消 ctx,触发退出
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
defer stop()
// 1. 创建客户端(不做网络请求)
cli, err := im.New(im.Config{
AppKey: "1575529652#demo",
APIURL: "https://im.example.com",
})
if err != nil {
panic(err)
}
// 2. 登录:生产用凭证;开发测试可用 im.LoginPassword
ticket, err := fetchTicket()
if err != nil {
panic(err)
}
if _, err := cli.Login(ctx, im.LoginTicket, "alice", ticket); err != nil {
panic(err)
}
// 3. 订阅事件:收到文本消息时打印并回复一句
cli.OnEvent(func(e im.Event) {
if e.Name != im.EventMessageReceived {
return
}
var m im.Message
if json.Unmarshal(e.Data, &m) != nil {
return
}
fmt.Printf("来自 %s:%s\n", m.Sender, m.TextBody())
go func() {
sendCtx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
if _, err := cli.SendText(sendCtx, im.ToUser(m.Sender), "收到:"+m.TextBody(), nil); err != nil {
fmt.Println("回复失败:", err)
}
}()
})
// 4. 建立长连接并等待认证完成,然后全量同步一次
if err := cli.ConnectWait(ctx); err != nil {
panic(err)
}
fmt.Println("已连接,Ctrl+C 退出")
if n, err := cli.SyncAll(ctx); err != nil {
fmt.Println("同步失败:", err)
} else {
fmt.Printf("已同步 %d 个会话\n", n)
}
// 5. 等待退出信号,优雅退出
<-ctx.Done()
fmt.Println("退出中…")
logoutCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
_ = cli.Logout(logoutCtx)
}运行
go mod tidy
IM_TICKET=ult_xxx go run .再用另一个账号(或 Web 端)给这个用户发消息,程序会打印收到的内容并自动回复。发送目标换成 im.ToGroup("群 ID") 就能把机器人拉进群里用。
密码登录只在开发测试时用
示例中的 im.LoginTicket 是生产环境的登录方式。开发调试时可以把登录一行换成 cli.Login(ctx, im.LoginPassword, "alice", "pass-123"),省去签发凭证的步骤;正式程序中不要内嵌密码。
