发送非文本类消息,如图片 (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
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,并替换内容字段。
// 以图片消息为例 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}$)。超限会导致上传失败。
权限:确保应用具有发送文件/图片消息的权限。