加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

使用delphi+intraweb进行微信开发5—准备实现微信API,先从获取A

发布时间:2020-12-15 09:54:18 所属栏目:大数据 来源:网络整理
导读:在前4讲中我们已经使iw开发的应用成功和微信进行了对接,再接下来的章节中我们开始逐一尝试和实现微信的各个API, 开始前先来点准备工作 首先需要明确的是,微信的API都是通过https调用实现的,分为 post方法 调用和 get方法 调用。不需要上传数据的采用get
在前4讲中我们已经使iw开发的应用成功和微信进行了对接,再接下来的章节中我们开始逐一尝试和实现微信的各个API,开始前先来点准备工作
  1. 首先需要明确的是,微信的API都是通过https调用实现的,分为post方法调用和get方法调用。不需要上传数据的采用get方法(例如获取AccessToken),而需要向微信服务器提交数据的采用post方法(例如创建菜单)。
  2. 微信方法调用均需传递AccessToken(URL参数方式),这个AccessToken不是我们微信接入时使用的Token,这个AccessToken专门用于微信API调用,AccessToken有过期时间,而且每天有请求次数限制,据说是为了防止不良的程序调用导致微信服务器出现异常。因此在这种情况下则必须在获取AccessToken后进行保存,在即将过期前再重新获取。
好吧,让我们开始:首先定义post和get方法。这里我们采用Indy实现,不需要再安装什么第三方组件了,也没有大量并发的要求(咱们这是客户端程序),简单易用最重要。

?

///?<summary>?
///?向指定URL发起Get请求?
///?</summary>?
///?<param?name="http">TIdHTTP</param>?
///?<param?name="URL">指定URL</param>?
///?<param?name="Max">Get请求失败最大重试次数</param>?
///?<returns>返回腾讯服务器响应(string类型的json格式数据)</returns>?
function?GetMethod(http:?TIdHTTP;?URL:?String;?Max:?Integer):?String;

var?
??RespData:?TStringStream;?
begin?
??RespData?:=?TStringStream.Create(‘‘,?TEncoding.UTF8);?
??try?
????try?
??????http.Get(URL,?RespData);?
??????http.Request.Referer?:=?URL;?
??????Result?:=?RespData.DataString;?
????except?
??????Dec(Max);?
??????if?Max?=?0?then?
??????begin?
????????Result?:=?‘‘;?
????????exit;?
??????end;?
??????Result?:=?GetMethod(http,?URL,?Max);?
????end;?
??finally?
????FreeAndNil(RespData);?
??end;?
end;?

///?<summary>?
///?向指定URL提交数据(Post)?
///?</summary>?
///?<param?name="http">TIdHTTP</param>?
///?<param?name="URL">指定URL</param>?
///?<param?name="Data">要提交的数据(UTF8String)</param>?
///?<param?name="Max">Post请求失败最大重试次数</param>?
///?<returns>返回腾讯服务器响应(string类型的json格式数据)</returns>?
function?PostMethod(http:?TIdHTTP;?URL:?String;?Data:?UTF8String;?
? ??Max:?Integer):?String;?

var?
??PostData,?RespData:?TStringStream;?
begin?
??RespData?:=?TStringStream.Create(‘‘);?
??PostData?:=?TStringStream.Create(Data);?
??try?
????try?
??????if?http?=?nil?then?
????????exit;?
??????http.Post(URL,?PostData,?RespData);?
??????Result?:=?RespData.DataString;?
??????http.Request.Referer?:=?URL;?
????except?
??????Dec(Max);?
??????if?Max?=?0?then?
??????begin?
????????Result?:=?‘‘;?
????????exit;?
??????end;?
??????Result?:=?PostMethod(http,?Data,?Max);?
????end;?
??finally?
????http.Disconnect;?
????FreeAndNil(RespData);?
????FreeAndNil(PostData);?
??end;?
end;?

有了上面两个方法我们就可以开始测试微信API了。

??不过你有没有注意到,微信请求是https,不是http啊,所以似乎还需要让Indy支持ssl传输才行啊,这当然没有问题,上Indy官网下载SSL支持DLL即可,分为64位和32位版本不要搞错,下载后和编译好的IW程序放置在同一目录下即可(说实在的下载网站我给忘了,大家可以百度一下,如果找不到给我留言,我把我下载的发出来)。

?

接下来研究下如何获取这个AccessToken

?

由于AccessToken在API调用中都需要使用,因此先来获取AccessToken吧,关于AccessToken的解释请看微信文档:http://mp.weixin.qq.com/wiki/14/9f9c82c1af308e3b14ba9b973f99a8ba.html

使用的微信命令URL是:https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET

采用Get方法。

如你所见:

1、URL调用需传递【APPID】和【APPSECRET】两个参数,返回结果为Json格式字符串。

2、调用成功的情况下,微信会返回下述JSON数据包给公众号:

{"access_token":"ACCESS_TOKEN","expires_in":7200}
参数 说明
access_token 获取到的凭证
expires_in 凭证有效时间,单位:秒


3、错误时微信会返回错误码等信息,JSON数据包示例如下(该示例为AppID无效错误):

{"errcode":40013,"errmsg":"invalid appid"}

??好吧,好像还得找个Json解析的组件,嗯嗯,够麻烦的,推荐使用第三方组件“SuperObject”进行Json格式解析,不过你要非得自行进行Json字符串编解码也行,嗯,可能会累点,相信我,最好找个封装完善的Json组件,工欲善其事必先利其器,否则创建菜单什么的时候有你受的。

?

嗯,Json结果解析判断什么的我就不说了,再说说AccessToken的缓存问题。

?

简单说:“为了保密appsecrect,第三方需要一个access_token获取和刷新的中控服务器。而其他业务逻辑服务器所使用的access_token均来自于该中控服务器,不应该各自去刷新,否则会造成access_token覆盖而影响业务;”这个是微信文档原话,所以让我们看看怎么缓存这个东东。

?先声明一个TAccessToken记录,然后利用一个全局公开的变量,再加上一个泛型容器,如此的简单:

///?<summary>?
///?AccessToken记录,包含AccessToken值和过期时间?
///?</summary>?
TAccessToken?=?record?
??AccessToken:?string;?
??AccessTokenExpiresDt:?TDateTime;?
end;

var?
??gAccessTokenLst:?TDictionary<string,?TAccessToken>;?
??gCS:?TCriticalSection;

???声明成记录类型的好处是,可以当做简单变量来使用,要是声明成指针或者类,哦哦,创建再释放,太麻烦了。微信返回的json结果中是这个AccessToken还有多少秒过期,我们换算成时间类型会比较好用一些。

??泛型我喜欢,让Hash表成为强类型的。

???如上gAccessTokenLst用来存储获取的AccessToken,key就是微信号的APPID,估计这个不会重复吧!上面还声明了一个临界区对象gCS,大约我不说你也能猜到,既然是全局的那就得上锁,防止写入混乱。

???上面那两个变量gAccessTokenLst和gCS我是在单元的initialization部分实例化的,并在finalization进行了释放,在这两个地方处理全局变量的好处是:运行时只执行一次。是初始化全局变量的绝佳地点。

?

万事具备了,最终获取AccessToken的函数代码如下:

?

procedure?TWxSdkImp.GetAccessToken(const?appid,?appsecret:?string;?
??var?AccessToken:?string;?const?GetNew:?Boolean = false);?
var?
??URL:?string;?
??JSONObject:?ISuperObject;?
??temp,?sKey:?string;?
??recAccessToken:?TAccessToken;?
begin?
??if?(appid?=?‘‘)?or?(appsecret?=?‘‘)?then?
????raise?Exception.Create(‘TWxSdkImp.GetAccessToken执行出错,参数应用ID或者应用秘钥不能为空!‘);?

??recAccessToken.AccessToken?:=?‘‘;?
??sKey?:=?appid;?
??if?gAccessTokenLst.ContainsKey(sKey)?then?
????recAccessToken?:=?gAccessTokenLst.Items[sKey];?

??//?如果要求重新获取AccessToken?或者?尚未获取AccessToken?或者?已经获取了但是离过期不足30秒?
??gCS.Enter;?
??try?
????if?GetNew?or?(recAccessToken.AccessToken?=?‘‘)?or?(SecondSpan(recAccessToken.AccessTokenExpiresDt,?Now)?<?30)?then?
????begin?
??????URL?:=?Format(WxCmdUrl_GetAccessToken,?[appid,?appsecret]);?
??????temp?:=?GetMethod(http,?3);?
??????JSONObject?:=?ParseJson(temp,?[‘"access_token"‘,?‘"errcode"‘]);?
??????if?Pos(‘"access_token"‘,?temp)?>?0?then?
??????begin?
????????recAccessToken.AccessToken?:=?JSONObject[‘access_token‘].AsString;?
????????recAccessToken.AccessTokenExpiresDt?:=?IncSecond(Now,?JSONObject[‘expires_in‘].AsInteger);?

????????if?gAccessTokenLst.ContainsKey(sKey)?then?
??????????gAccessTokenLst.Remove(sKey);?
????????gAccessTokenLst.Add(sKey,?recAccessToken);?
??????end?else?
????????raise?Exception.Create(‘TWxSdkImp.GetAccessToken执行出错,服务器返回错误代码:‘?+?JSONObject[‘errcode‘].AsString?+?‘,错误信息:‘?+?JSONObject[‘errmsg‘].AsString?+?‘!‘);?
????end;?

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读