8.3 上传素材
开发者发送给用户的消息中图片消息、小程序卡片消息包含有媒体ID,媒体ID是开发者上传媒体文件(图片文件、视频文件等)到微信服务器的后由微信服务器返回的一个媒体编码。上传媒体文件的接口称为素材接口,由于发送图片消息、小程序卡片消息需要提供媒体ID,因此在介绍发送客服消息前我们先介绍如何调用素材接口来上传媒体文件,并获取媒体ID。
注意点:
- 临时素材media_id是可复用的。
- 媒体文件在微信后台保存时间为3天,即3天后media_id失效,目前小程序不支持永久素材上传。
- 目前仅支持图片文件上传,图片支持PNG\JPEG\JPG\GIF格式
请求地址
api.weixin.qq.com/cgi-bin/media/upload?access_token=ACCESS_TOKEN&type=TYPE
参数说明
- access_token:调用接口凭证
- type:媒体文件类型,分别有图片(image)、语音(voice)、视频(video)和缩略图(thumb)
- media:form-data中媒体文件标识,有filename、filelength、content-type等信息
返回值
返回的 JSON 数据包的字段:
- errcode:错误码
- errmsg:错误信息
- type:文件类型
- media_id:媒体文件上传后,获取标识,3天内有效。
- created_at:媒体文件上传时间戳
上传媒体文件的示例代码:
//使用multipart/form-data发送文件
func PostFileByFormData(url string, params map[string]string, file_path string, file_key string) (string, error) {
file, err := os.Open(file_path)
defer file.Close()
if err != nil {
log.Println("err")
return "", err
}
defer file.Close()
bodyBuf := &bytes.Buffer{}
bodyWrite := multipart.NewWriter(bodyBuf)
for key, val := range params {
_ = bodyWrite.WriteField(key, val)
}
fileWrite, err := bodyWrite.CreateFormFile(file_key, file.Name())
_, err = io.Copy(fileWrite, file)
if err != nil {
log.Println("err")
return "", err
}
bodyWrite.Close()
client := http.Client{}
req, err := http.NewRequest(http.MethodPost, url, bodyBuf)
if err != nil {
log.Println("err")
return "", err
}
req.Header.Set("Content-Type", bodyWrite.FormDataContentType())
resp, err := client.Do(req)
if err != nil {
log.Println("err")
return "", err
}
defer resp.Body.Close()
result, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Fatal("Error:", err)
return "", err
}
if resp.StatusCode != 200 {
err := fmt.Errorf("status:%d", resp.StatusCode)
return string(result),err
}
return string(result), nil
}
PostFileByFormData函数用于向服务器上传文件,并支持键值对的发送。由于素材接口上传的是图片文件,并要求按照FormData上传,因此PostFileByFormData函数中使用HTTP的POST方法请求URL对应的接口,并且采用multipart/form-data的编码格式发送数据。接下来是调用素材接口的进行媒体文件上传的代码:
//媒体文件上传返回结果
type UploadTempMediaRet struct {
ErrCode int64 `json:"errcode"`
ErrMsg string `json:"errmsg"`
FileType string `json:"type"`
MediaId string `json:"media_id"`
CreatedTime int64 `json:"created_at"`
}
//把媒体文件上传到微信服务器,目前仅支持图片
func UploadTempMedia(access_token string, file_path string) (error, UploadTempMediaRet) {
wx_addr := "https://api.weixin.qq.com/cgi-bin/media/upload"
wx_addr += "?access_token=" + access_token
wx_addr += "&type=image"
var ret UploadTempMediaRet
result, err := PostFileByFormData(wx_addr, nil, file_path, "media")
if err != nil {
fmt.Println(err)
return err, ret
}
err = json.Unmarshal([]byte(result), &ret)
if err != nil {
fmt.Println(err)
return err, ret
}
return nil, ret
}
8.4 发送客服消息
当用户和小程序客服产生特定动作的交互时,开发者可以在一段时间内(目前为48小时)调用客服接口,通过调用发送客服消息接口来给普通用户发送消息。
请求地址
api.weixin.qq.com/cgi-bin/message/custom/send?access_token=ACCESS_TOKEN
请求参数
- access_token:接口调用凭证
- touser:用户的 OpenID
- msgtype:消息类型
- text:文本消息,msgtype=“text” 时必填
- image:图片消息,msgtype=“image” 时必填
- link:图文链接,msgtype=“link” 时必填
- miniprogrampage:小程序卡片,msgtype=“miniprogrampage” 时必填
返回值
返回的 JSON 数据包
- errcode:错误码
- errmsg:错误信息
msgtype 的合法值 - text:文本消息
- image:图片消息
- link:图文链接
- miniprogrampage:小程序卡片
文本消息
{
"touser":"OPENID",
"msgtype":"text",
"text":
{
"content":"Hello World"
}
}
图片消息
{
"touser":"OPENID",
"msgtype":"image",
"image": {
"media_id":"MEDIA_ID"
}
}
图文链接
{
"touser": "OPENID",
"msgtype": "link",
"link": {
"title": "Happy Day",
"description": "Is Really A Happy Day",
"url": "URL",
"thumb_url": "THUMB_URL"
}
}
小程序卡片
{
"touser":"OPENID",
"msgtype":"miniprogrampage",
"miniprogrampage": {
"title":"title",
"pagepath":"pagepath",
"thumb_media_id":"thumb_media_id"
}
}
另外发送文本消息时,支持添加可跳转小程序的文字连接,例如:
点击跳小程序 说明:
- data-miniprogram-appid项,填写小程序appid,则表示该链接跳转小程序;
- data-miniprogram-path项,填写小程序路径,路径与app.json中保持一致,可带参数;
- 对于不支持 data-miniprogram-appid 项的客户端版本(6.5.16 以下),如果有herf项,则仍然保持跳href中的链接;
- 小程序发带小程序文字链的文本消息,data-miniprogram-appid必须是该小程序的appid。
接下来介绍客服消息的发送相关的代码,首先是各种消息结构的定义:
//微信消息内容对应的结构:文本消息
type WxMsgText struct {
Content string `json:"content"`
}
//微信消息内容对应的结构:图片消息
type WxMsgImage struct {
MediaId string `json:"media_id"`
}
//微信消息内容对应的结构:图文链接
type WxMsgLink struct {
Title string `json:"title"`
Description string `json:"description"`
Url string `json:"url"`
ThumbUrl string `json:"thumb_url"`
}
//微信消息内容对应的结构:小程序卡片
type WxMsgWsa struct {
Title string `json:"title"`
PagePath string `json:"pagepath"`
ThumbMediaId string `json:"thumb_media_id"`
}
//发送客服消息给用户
type WxMsgSend struct {
ToUser string `json:"touser"`
MsgType string `json:"msgtype"`
Text *WxMsgText `json:"text,omitempty"`
Image *WxMsgImage `json:"image,omitempty"`
Link *WxMsgLink `json:"link,omitempty"`
WxaPage *WxMsgWsa `json:"miniprogrampage,omitempty"`
}
上面的代码没有为每种消息类型定义一个对应的类型,而是把所有的消息类型定义为类型:WxMsgSend,使用时通过json:"omitempty属性来控制字段是否编码到json字符串中。接下来是客服消息发送的代码:
//发送客服消息给用户
func SendfWxKfMsg(ent WxMsgSend, access_token string) error {
wx_addr := "https://api.weixin.qq.com/cgi-bin/message/custom/send"
wx_addr += "?access_token=" + access_token
data, _ := json.Marshal(ent)
res, err := http.Post(wx_addr, "charset=UTF-8", bytes.NewReader(data))
if err != nil {
return err
}
_, err = ioutil.ReadAll(res.Body)
res.Body.Close()
if err != nil {
return err
}
return nil
}