发送非文本类消息,如图片 (msgtype: image) 或文件 (msgtype: file),不能直接将文件数据包含在 POST 请求体中。企业微信要求开发者首先将素材上传到服务器,获取一个临时的唯一标识符:media_id ,然后再将此 media_id 用于构建最终的消息体。
1. 两步走的核心流程
-
上传素材: 调用
/cgi-bin/media/upload接口,将本地文件以multipart/form-data的形式上传到企业微信服务器。服务器返回一个临时的media_id。 -
发送消息: 调用
/cgi-bin/appchat/send接口,在请求体中用获取到的media_id替换掉原有的文本内容。
2. 第一步:Go 实现素材上传
素材上传需要使用 multipart/form-data 格式,这是 Go 语言中一个相对复杂的网络操作,需要用到 mime/multipart 包。
2.1 上传 API 接口
-
请求方式: POST
-
请求 URL:
https://qyapi.weixin.qq.com/cgi-bin/media/upload?access_token=ACCESS_TOKEN&type=TYPETYPE:素材类型,如image、file、voice等。
2.2 Go 上传实现思路
-
创建 Pipeline: 使用
bytes.Buffer配合mime/multipart.Writer来构造multipart/form-data的请求体。 -
写入文件字段:
-
使用
writer.CreateFormFile(fieldname, filename)创建一个文件字段,并返回一个io.Writer。 -
将本地文件的内容通过
io.Copy()写入到这个io.Writer中。
-
-
设置 Content-Type: 关键在于,HTTP 请求头中的
Content-Type必须设置为multipart/form-data,并且其边界(Boundary)值必须与multipart.Writer自动生成的边界值保持一致。 -
执行 POST 请求: 发送包含文件内容的 HTTP POST 请求。
-
解析响应: 接收响应 JSON,解析到对应的 Struct 中,获取
media_id。
2.3 核心返回 Struct
Go
type UploadResponse struct {
ErrCode int `json:"errcode"`
ErrMsg string `json:"errmsg"`
Type string `json:"type"`
MediaID string `json:"media_id"` // 核心字段
}
3. 第二步:Go 实现消息发送
获取 media_id 后,发送消息就回归到 帖子 17 中的 JSON 构造和 POST 流程。
3.1 消息 Struct 定义
只需要将 msgtype 设置为 image 或 file,并替换内容字段。
Go
// 以图片消息为例
type ImageContent struct {
MediaID string `json:"media_id"` // 使用上传获取到的 ID
}
type SendImageMessageRequest struct {
ChatID string `json:"chatid"`
MsgType string `json:"msgtype"` // "image"
Image ImageContent `json:"image"`
}
3.2 发送流程
-
实例化
SendImageMessageRequest,将上一步获得的media_id填入。 -
使用
json.Marshal序列化为 JSON 字节流。 -
构造 POST 请求,发送到
/cgi-bin/appchat/send接口。
4. 关键注意事项
-
素材有效期: 上传的临时素材
media_id仅在三天内有效,且只能被用于一次消息发送。因此,每次发送非文本消息前,几乎都需要执行一次上传操作。 -
文件大小限制: 不同类型的素材有严格的大小限制(例如,图片最大 2\\text{MB},文件最大 20\\text{MB})。超限会导致上传失败。
-
权限: 确保应用具有发送文件/图片消息的权限。