跟我一起学微信公众平台开发(四)
前一阵子,受困于以form-data格式post方法上传文件的困惑,导致我的微信公众号开发受阻,迟迟没有进展。。。25号晚上1点多钟,脑子突然灵光一闪,那个问题不费吹灰之力就解决了,之前求助deepseek也没有解决。我把解决方法反哺给deepseek了,以后有同样问题它就可以正确解答了。
今天,微信公众号的素材管理模块的工作总算是完成了(有待完善),赶紧发上来分享给大家,就当是祝大家新年快乐。。。
谈谈开发思路,供感兴趣的狐友参考。
微信的素材管理有7个功能接口,新增临时素材,获取临时素材(这两个没有对我开放权限),新增永久素材,获取永久素材,删除永久素材,获取素材总数, 获取素材列表。因为功能差不多,所以我把他们整合到一个类里面,建立一个自定义类materials,分别用append,get,delete,getcount,getlist方法来实现这几个功能。还有一个uploadimg方法,是用来上传图文信息里的图片的,就是这个玩意让我苦思冥想很久。。。
现在把这个materials类的代码发上来,有感兴趣的,可以私信我要源代码,我的myclass有点大好像不能上传
这里是主要代码:
程序代码:
************************************************** *-- 类: materials (d:\my documents\visual foxpro 项目\myclass.vcx) *-- 父类: custom *-- 基类: custom *-- 时间戳: 01/28/25 11:06:06 PM * DEFINE CLASS materials AS custom *-- 微信素材库api网址 apiurl = "" *-- 上传素材的类型,默认为image。 type = "image" Name = "materials" *-- 新增永久素材 PROCEDURE append *!* 新增临时素材 http请求方式:POST/FORM,使用https https://api.weixin./cgi-bin/media/upload?access_token=ACCESS_TOKEN&type=TYPE *!* 获取临时素材 http请求方式: GET,https调用 https://api.weixin./cgi-bin/media/get?access_token=ACCESS_TOKEN&media_id=MEDIA_ID *!* 新增永久素材 http请求方式: POST,https协议 https://api.weixin./cgi-bin/media/uploadimg?access_token=ACCESS_TOKEN *!* 获取永久素材 http请求方式: POST,https协议 https://api.weixin./cgi-bin/material/get_material?access_token=ACCESS_TOKEN *!* 删除永久素材 http请求方式: POST https://api.weixin./cgi-bin/material/del_material?access_token=ACCESS_TOKEN *!* 获取素材总数 http请求方式: GET https://api.weixin./cgi-bin/material/get_materialcount?access_token=ACCESS_TOKEN *!* 获取素材列表 http请求方式: POST https://api.weixin./cgi-bin/material/batchget_material?access_token=ACCESS_TOKEN *!* 素材的格式大小等要求 *!* 图片(image): 10M,支持bmp/png/jpeg/jpg/gif格式 *!* 语音(voice):2M,播放长度不超过60s,mp3/wma/wav/amr格式 *!* 视频(video):10MB,支持MP4格式 *!* 缩略图(thumb):64KB,支持JPG格式 PARAMETERS mediafile *!* 如果没有给mediafile参数 IF PARAMETERS()=0 DO CASE CASE this.type="image" mediafile=GETFILE("bmp|jpeg|jpg|png|gif") CASE this.type="voice" mediafile=GETFILE("mp3|wma|wav|amr") CASE this.type="video" mediafile=GETFILE("mp4") CASE this.type="thumb" mediafile=GETFILE("jpg") OTHERWISE MESSAGEBOX("微信素材只支持图片、语音、视频和缩略图!",0+16,"请设置正确的素材type!") RETURN ENDCASE ENDIF *!* 检查文件大小并设置mine类型 opart=NEWOBJECT("part","myclass") opart.fieldname="media" &&设定接口字段名为media cstr=FILETOSTR(mediafile) nlen=LEN(cstr) DO CASE CASE this.type="image" IF nlen>10*1024*1024 OR nlen=0 MESSAGEBOX("文件大小超过 10MB!",0+16,"上传失败!") RELEASE opart RETURN ENDIF opart.contenttype="image/"+IIF(LOWER(JUSTEXT(mediafile))="jpg","jpeg",LOWER(JUSTEXT(mediafile))) CASE this.type="voice" IF nlen>2*1024*1024 OR nlen=0 MESSAGEBOX("文件大小超过 2MB!",0+16,"上传失败!") RELEASE opart RETURN ENDIF opart.contenttype="audio/"+ICASE(LOWER(JUSTEXT(mediafile))="mp3","mpeg",LOWER(JUSTEXT(mediafile))="wma","x-ms-wma",LOWER(JUSTEXT(mediafile))) CASE this.type="video" IF nlen>10*1024*1024 OR nlen=0 MESSAGEBOX("文件大小超过 10MB!",0+16,"上传失败!") RELEASE opart RETURN ENDIF opart.contenttype="video/mp4" CASE this.type="thumb" IF nlen>64*1024 OR nlen=0 MESSAGEBOX("文件大小超过 64KB!",0+16,"上传失败!") RELEASE opart RETURN ENDIF opart.contenttype="image/jpeg" OTHERWISE MESSAGEBOX("微信素材只支持图片、语音、视频和缩略图!",0+16,"请设置正确的素材type!") RELEASE oport RETURN ENDCASE opart.attachment=mediafile *!* 准备请求体 omultipart=NEWOBJECT("multipart","myclass") omultipart.parts.add(opart) *!* 下面这段逻辑有点问题,没考虑好在什么环境下使用 IF this.type="video/mp4" &&微信要求上传视频时还要提交视频描述信息,json结构 opart2=NEWOBJECT("part","myclass") opart2.contenttype="application/json" opart2.fieldname="description" opart2.append("id","description") *!* 构建json格式数据,格式如下 *!* { *!* "title":VIDEO_TITLE, *!* "introduction":INTRODUCTION *!* } *!* ojson应该在此方法前构建好,这里就当是检查是否遗漏 * IF EMPTY(opart2.content) ojson=NEWOBJECT("json","myclass") ctitle=INPUTBOX("请在文本框中输入您想显示的视频标题!","请提供视频的标题!") ojson.add("title",ctitle) cdescription=INPUTBOX("请在文本框中输入您想显示的视频描述,越详细越好。","请提供视频的描述!") ojson.add("introduction",cdescription) opart2.content=ojson.generate() RELEASE ojson * ENDIF omultipart.parts.add(opart2) ENDIF *!* omultipart.setrequestheader() omultipart.setrequestbody() lcheader=omultipart.contenttype+omultipart.boundary lcbody=CREATEBINARY(omultipart.requestbody) STRTOFILE(lcbody,"request_body.txt") && debug,成功后注释掉。 RELEASE opart,omultipart this.apiurl="https://api.weixin./cgi-bin/material/add_material?access_token=ACCESS_TOKEN&type=TYPE" this.apiurl=STRTRAN(this.apiurl,"ACCESS_TOKEN",otoken.access_token) this.apiurl=STRTRAN(this.apiurl,"TYPE",this.type) * 准备发送 HTTP POST 请求 LOCAL loHTTP, lcResponse *loHTTP = CREATEOBJECT("WinHttp.WinHttpRequest.5.1") lohttp=NEWOBJECT("microsoft.xmlhttp") *loHTTP.SetProxy(2, "127.0.0.1:8888") && 设置代理,方便调试,没问题后可以注释掉 loHTTP.Open("POST", this.apiurl, .F.) *loHTTP.SetRequestHeader("Accept-Encoding","gzip, deflate, br") *loHttp.SetRequestHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36") loHTTP.SetRequestHeader("Content-Type", lcHeader) *loHTTP.SetRequestHeader("Content-Length", LEN(lcbody)) loHTTP.Send(lcBody) WAIT "数据上传中。。。" WINDOW AT 25,90 TIMEOUT 5 lcresponse=lohttp.responsetext RELEASE lohttp * 获得服务器响应文本,调试用,完成后可以注释掉 STRTOFILE(lcresponse,"response.txt") MODIFY FILE response.txt nowait ENDPROC *-- 删除永久素材 PROCEDURE delete *!* 新增临时素材 http请求方式:POST/FORM,使用https https://api.weixin./cgi-bin/media/upload?access_token=ACCESS_TOKEN&type=TYPE *!* 获取临时素材 http请求方式: GET,https调用 https://api.weixin./cgi-bin/media/get?access_token=ACCESS_TOKEN&media_id=MEDIA_ID *!* 新增永久素材 http请求方式: POST,https协议 https://api.weixin./cgi-bin/media/uploadimg?access_token=ACCESS_TOKEN *!* 获取永久素材 http请求方式: POST,https协议 https://api.weixin./cgi-bin/material/get_material?access_token=ACCESS_TOKEN *!* 删除永久素材 http请求方式: POST https://api.weixin./cgi-bin/material/del_material?access_token=ACCESS_TOKEN *!* 获取素材总数 http请求方式: GET https://api.weixin./cgi-bin/material/get_materialcount?access_token=ACCESS_TOKEN *!* 获取素材列表 http请求方式: POST https://api.weixin./cgi-bin/material/batchget_material?access_token=ACCESS_TOKEN PARAMETERS media_id this.apiurl="https://api.weixin./cgi-bin/material/del_material?access_token=ACCESS_TOKEN" this.apiurl=STRTRAN(this.apiurl,"ACCESS_TOKEN",otoken.access_token) ohttp.open("POST",lcurl,.f.) cjson="{"+["]+"media_id"+[": ]+["]+media_id+["]+"}" ohttp.send(cjson) WAIT "正在连接服务器。。。" WINDOW AT 25,90 TIMEOUT 3 STRTOFILE(ohttp.responsetext,"response.txt") MODIFY FILE response.txt nowait RELEASE ohttp ENDPROC *-- 获取永久素材的总数 PROCEDURE getcount *!* 新增临时素材 http请求方式:POST/FORM,使用https https://api.weixin./cgi-bin/media/upload?access_token=ACCESS_TOKEN&type=TYPE *!* 获取临时素材 http请求方式: GET,https调用 https://api.weixin./cgi-bin/media/get?access_token=ACCESS_TOKEN&media_id=MEDIA_ID *!* 新增永久素材 http请求方式: POST,https协议 https://api.weixin./cgi-bin/media/uploadimg?access_token=ACCESS_TOKEN *!* 获取永久素材 http请求方式: POST,https协议 https://api.weixin./cgi-bin/material/get_material?access_token=ACCESS_TOKEN *!* 删除永久素材 http请求方式: POST https://api.weixin./cgi-bin/material/del_material?access_token=ACCESS_TOKEN *!* 获取素材总数 http请求方式: GET https://api.weixin./cgi-bin/material/get_materialcount?access_token=ACCESS_TOKEN *!* 获取素材列表 http请求方式: POST https://api.weixin./cgi-bin/material/batchget_material?access_token=ACCESS_TOKEN this.apiurl="https://api.weixin./cgi-bin/material/get_materialcount?access_token=ACCESS_TOKEN" this.apiurl=STRTRAN(this.apiurl,"ACCESS_TOKEN",otoken.access_token) lohttp=NEWOBJECT("microsoft.xmlhttp") lohttp.open("GET",this.apiurl,.f.) lohttp.send() WAIT "发送请求。。。" WINDOW AT 25,90 TIMEOUT 3 lcresponse=lohttp.responsetext RELEASE lohttp * 获得服务器响应文本,调试用 STRTOFILE(lcresponse,"response.txt") MODIFY FILE response.txt nowait *!* 返回说明 *!* { *!* "voice_count":COUNT, *!* "video_count":COUNT, *!* "image_count":COUNT, *!* "news_count":COUNT *!* } ENDPROC *-- 获取指定类型的素材列表 PROCEDURE getlist *!* 新增临时素材 http请求方式:POST/FORM,使用https https://api.weixin./cgi-bin/media/upload?access_token=ACCESS_TOKEN&type=TYPE *!* 获取临时素材 http请求方式: GET,https调用 https://api.weixin./cgi-bin/media/get?access_token=ACCESS_TOKEN&media_id=MEDIA_ID *!* 新增永久素材 http请求方式: POST,https协议 https://api.weixin./cgi-bin/media/uploadimg?access_token=ACCESS_TOKEN *!* 获取永久素材 http请求方式: POST,https协议 https://api.weixin./cgi-bin/material/get_material?access_token=ACCESS_TOKEN *!* 删除永久素材 http请求方式: POST https://api.weixin./cgi-bin/material/del_material?access_token=ACCESS_TOKEN *!* 获取素材总数 http请求方式: GET https://api.weixin./cgi-bin/material/get_materialcount?access_token=ACCESS_TOKEN *!* 获取素材列表 http请求方式: POST https://api.weixin./cgi-bin/material/batchget_material?access_token=ACCESS_TOKEN this.apiurl="https://api.weixin./cgi-bin/material/batchget_material?access_token=ACCESS_TOKEN" this.apiurl=STRTRAN(this.apiurl,"ACCESS_TOKEN",otoken.access_token) ojson=NEWOBJECT("json","myclass") ojson.Add("image","type") ojson.Add(0,"offset") ojson.Add(1,"count") cjson=ojson.generate() ohttp.open("POST",lcurl,.f.) ohttp.send(cjson) WAIT "正在连接服务器。。。" WINDOW AT 25,90 TIMEOUT 3 STRTOFILE(ohttp.responsetext,"response.txt") MODIFY FILE response.txt nowait RELEASE ojson,ohttp ENDPROC *-- 获取永久素材 PROCEDURE get *!* 新增临时素材 http请求方式:POST/FORM,使用https https://api.weixin./cgi-bin/media/upload?access_token=ACCESS_TOKEN&type=TYPE *!* 获取临时素材 http请求方式: GET,https调用 https://api.weixin./cgi-bin/media/get?access_token=ACCESS_TOKEN&media_id=MEDIA_ID *!* 新增永久素材 http请求方式: POST,https协议 https://api.weixin./cgi-bin/media/uploadimg?access_token=ACCESS_TOKEN *!* 获取永久素材 http请求方式: POST,https协议 https://api.weixin./cgi-bin/material/get_material?access_token=ACCESS_TOKEN *!* 删除永久素材 http请求方式: POST https://api.weixin./cgi-bin/material/del_material?access_token=ACCESS_TOKEN *!* 获取素材总数 http请求方式: GET https://api.weixin./cgi-bin/material/get_materialcount?access_token=ACCESS_TOKEN *!* 获取素材列表 http请求方式: POST https://api.weixin./cgi-bin/material/batchget_material?access_token=ACCESS_TOKEN PARAMETERS media_id this.apiurl="https://api.weixin./cgi-bin/material/get_material?access_token=ACCESS_TOKEN" this.apiurl=STRTRAN(this.apiurl,"ACCESS_TOKEN",otoken.access_token) ohttp.open("POST",lcurl,.f.) cjson="{"+["]+"media_id"+[": ]+["]+media_id+["]+"}" ohttp.send(cjson) WAIT "正在连接服务器。。。" WINDOW AT 25,90 TIMEOUT 3 STRTOFILE(ohttp.responsetext,"response.txt") MODIFY FILE response.txt nowait RELEASE ohttp ENDPROC *-- 新增临时素材 PROCEDURE appendtemp *!* 新增临时素材 http请求方式:POST/FORM,使用https https://api.weixin./cgi-bin/media/upload?access_token=ACCESS_TOKEN&type=TYPE *!* 获取临时素材 http请求方式: GET,https调用 https://api.weixin./cgi-bin/media/get?access_token=ACCESS_TOKEN&media_id=MEDIA_ID *!* 新增永久素材 http请求方式: POST,https协议 https://api.weixin./cgi-bin/media/uploadimg?access_token=ACCESS_TOKEN *!* 获取永久素材 http请求方式: POST,https协议 https://api.weixin./cgi-bin/material/get_material?access_token=ACCESS_TOKEN *!* 删除永久素材 http请求方式: POST https://api.weixin./cgi-bin/material/del_material?access_token=ACCESS_TOKEN *!* 获取素材总数 http请求方式: GET https://api.weixin./cgi-bin/material/get_materialcount?access_token=ACCESS_TOKEN *!* 获取素材列表 http请求方式: POST https://api.weixin./cgi-bin/material/batchget_material?access_token=ACCESS_TOKEN this.apiurl="https://api.weixin./cgi-bin/media/upload" ENDPROC *-- 获取临时素材 PROCEDURE gettemp *!* 新增临时素材 http请求方式:POST/FORM,使用https https://api.weixin./cgi-bin/media/upload?access_token=ACCESS_TOKEN&type=TYPE *!* 获取临时素材 http请求方式: GET,https调用 https://api.weixin./cgi-bin/media/get?access_token=ACCESS_TOKEN&media_id=MEDIA_ID *!* 新增永久素材 http请求方式: POST,https协议 https://api.weixin./cgi-bin/media/uploadimg?access_token=ACCESS_TOKEN *!* 获取永久素材 http请求方式: POST,https协议 https://api.weixin./cgi-bin/material/get_material?access_token=ACCESS_TOKEN *!* 删除永久素材 http请求方式: POST https://api.weixin./cgi-bin/material/del_material?access_token=ACCESS_TOKEN *!* 获取素材总数 http请求方式: GET https://api.weixin./cgi-bin/material/get_materialcount?access_token=ACCESS_TOKEN *!* 获取素材列表 http请求方式: POST https://api.weixin./cgi-bin/material/batchget_material?access_token=ACCESS_TOKEN this.apiurl="https://api.weixin./cgi-bin/media/get" ENDPROC *-- 新增图文信息内的图片素材 PROCEDURE uploadimg *!* 新增临时素材 http请求方式:POST/FORM,使用https https://api.weixin./cgi-bin/media/upload?access_token=ACCESS_TOKEN&type=TYPE *!* 获取临时素材 http请求方式: GET,https调用 https://api.weixin./cgi-bin/media/get?access_token=ACCESS_TOKEN&media_id=MEDIA_ID *!* 新增永久素材 http请求方式: POST,https协议 https://api.weixin./cgi-bin/media/uploadimg?access_token=ACCESS_TOKEN *!* 获取永久素材 http请求方式: POST,https协议 https://api.weixin./cgi-bin/material/get_material?access_token=ACCESS_TOKEN *!* 删除永久素材 http请求方式: POST https://api.weixin./cgi-bin/material/del_material?access_token=ACCESS_TOKEN *!* 获取素材总数 http请求方式: GET https://api.weixin./cgi-bin/material/get_materialcount?access_token=ACCESS_TOKEN *!* 获取素材列表 http请求方式: POST https://api.weixin./cgi-bin/material/batchget_material?access_token=ACCESS_TOKEN *!* 上传图文信息内的图片至微信公众号服务器,成功则返回图片的网址。图片仅支持jpg和png格式,不超过1M。 *!* 使用者拿到图片的网址后应保存在表中,方便日后读取。 PARAMETERS lcimgpng IF PARAMETERS()=0 lcimgpng=GETFILE("jpg|png") ENDIF * 检查文件大小及内容 lnFileSize = LEN(FILETOSTR(lcimgpng)) IF lnFileSize > 1 * 1024 * 1024 OR lnFileSize=0 MESSAGEBOX("文件大小超过 1MB!",0+16,"上传失败!") RETURN ENDIF * 准备上传诸元:接口字段名,附件,content-type,生成所需post的二进制数据流lcbody opart=NEWOBJECT("part","myclass") opart.fieldname="media" &&设定接口字段名为media opart.attachment=lcimgpng IF JUSTEXT(lcimgpng)="JPG" opart.contenttype="image/jpg" ENDIF IF JUSTEXT(lcimgpng)="PNG" opart.contenttype="image/png" ENDIF omultipart=NEWOBJECT("multipart","myclass") omultipart.parts.add(opart) omultipart.setrequestheader() omultipart.setrequestbody() lcheader=omultipart.contenttype+omultipart.boundary lcbody=CREATEBINARY(omultipart.requestbody) STRTOFILE(lcbody,"request_body.txt") && debug,成功后注释掉。 RELEASE opart,omultipart lcAccessToken = otoken.access_token && otoken是public对象,用来获得令牌access_token this.apiurl="https://api.weixin./cgi-bin/media/uploadimg?access_token=ACCESS_TOKEN" this.apiurl=STRTRAN(this.apiurl,"ACCESS_TOKEN",lcaccesstoken) * 准备发送 HTTP POST 请求的函数 LOCAL loHTTP, lcResponse *loHTTP = CREATEOBJECT("WinHttp.WinHttpRequest.5.1") lohttp=NEWOBJECT("microsoft.xmlhttp") *loHTTP.SetProxy(2, "127.0.0.1:8888") && 设置代理,方便调试,没问题后可以注释掉 loHTTP.Open("POST", this.apiurl, .F.) *loHTTP.SetRequestHeader("Accept-Encoding","gzip, deflate, br") *loHttp.SetRequestHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36") loHTTP.SetRequestHeader("Content-Type", lcHeader) *loHTTP.SetRequestHeader("Content-Length", LEN(lcbody)) loHTTP.Send(lcBody) WAIT "数据上传中。。。" WINDOW AT 25,90 TIMEOUT 5 lcresponse=lohttp.responsetext RELEASE lohttp * 获得服务器响应文本,调试用 STRTOFILE(lcresponse,"response.txt") MODIFY FILE response.txt nowait ENDPROC PROCEDURE Init *this.result=NEWOBJECT("json","myclass") *!* this.AddObject("paras","keyvalue") *!* this.AddObject("result","json") ENDPROC ENDDEFINE * *-- EndDefine: materials **************************************************