zoukankan      html  css  js  c++  java
  • 使用delphi+intraweb进行微信开发5—准备实现微信API,先从获取AccessToken开始

    https://www.cnblogs.com/dpower/

    看这个博客

    在前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(httpTIdHTTPURLStringMaxInteger): String;

    var 
      RespDataTStringStream
    begin 
      RespData := TStringStream.Create(''TEncoding.UTF8); 
      try 
        try 
          http.Get(URLRespData); 
          http.Request.Referer := URL
          Result := RespData.DataString
        except 
          Dec(Max); 
          if Max then 
          begin 
            Result := ''
            exit
          end
          Result := GetMethod(httpURLMax); 
        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(httpTIdHTTPURLStringDataUTF8String
        MaxInteger): String

    var 
      PostDataRespDataTStringStream
    begin 
      RespData := TStringStream.Create(''); 
      PostData := TStringStream.Create(Data); 
      try 
        try 
          if http nil then 
            exit
          http.Post(URLPostDataRespData); 
          Result := RespData.DataString
          http.Request.Referer := URL
        except 
          Dec(Max); 
          if Max then 
          begin 
            Result := ''
            exit
          end
          Result := PostMethod(httpURLDataMax); 
        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 
      AccessTokenstring
      AccessTokenExpiresDtTDateTime
    end;

    var 
      gAccessTokenLstTDictionary<stringTAccessToken>; 
      gCSTCriticalSection;

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

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

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

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

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

    procedure TWxSdkImp.GetAccessToken(const appidappsecretstring
      var AccessTokenstringconst GetNewBoolean = false); 
    var 
      URLstring
      JSONObjectISuperObject
      tempsKeystring
      recAccessTokenTAccessToken
    begin 
      if (appid ''or (appsecret ''then 
        raise Exception.Create('TWxSdkImp.GetAccessToken执行出错,参数应用ID或者应用秘钥不能为空!'); 

      recAccessToken.AccessToken := ''
      sKey := appid
      if gAccessTokenLst.ContainsKey(sKeythen 
        recAccessToken := gAccessTokenLst.Items[sKey]; 

      // 如果要求重新获取AccessToken 或者 尚未获取AccessToken 或者 已经获取了但是离过期不足30秒 
      gCS.Enter
      try 
        if GetNew or (recAccessToken.AccessToken ''or (SecondSpan(recAccessToken.AccessTokenExpiresDtNow30then 
        begin 
          URL := Format(WxCmdUrl_GetAccessToken[appidappsecret]); 
          temp := GetMethod(httpURL3); 
          JSONObject := ParseJson(temp['"access_token"''"errcode"']); 
          if Pos('"access_token"'tempthen 
          begin 
            recAccessToken.AccessToken := JSONObject['access_token'].AsString
            recAccessToken.AccessTokenExpiresDt := IncSecond(NowJSONObject['expires_in'].AsInteger); 

            if gAccessTokenLst.ContainsKey(sKeythen 
              gAccessTokenLst.Remove(sKey); 
            gAccessTokenLst.Add(sKeyrecAccessToken); 
          end else 
            raise Exception.Create('TWxSdkImp.GetAccessToken执行出错,服务器返回错误代码:' JSONObject['errcode'].AsString ',错误信息:' JSONObject['errmsg'].AsString '!'); 
        end
      finally 
        gCS.Leave
      end
      AccessToken := recAccessToken.AccessToken
    end;

    需要获取AccessToken时,

    var accessToken: string; 

    GetAccessToken('YourAppID', 'YourAppSecret', accessToken);

    输出的accessToken字符串就是我们想要的结果。

  • 相关阅读:
    LeetCode 81 Search in Rotated Sorted Array II(循环有序数组中的查找问题)
    LeetCode 80 Remove Duplicates from Sorted Array II(移除数组中出现两次以上的元素)
    LeetCode 79 Word Search(单词查找)
    LeetCode 78 Subsets (所有子集)
    LeetCode 77 Combinations(排列组合)
    LeetCode 50 Pow(x, n) (实现幂运算)
    LeetCode 49 Group Anagrams(字符串分组)
    LeetCode 48 Rotate Image(2D图像旋转问题)
    LeetCode 47 Permutations II(全排列)
    LeetCode 46 Permutations(全排列问题)
  • 原文地址:https://www.cnblogs.com/westsoft/p/9940278.html
Copyright © 2011-2022 走看看