使用delphi+intraweb進行微信開發5—准備實現微信API,先從獲取AccessToken開始


在前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
  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(http: TIdHTTP; URL: String; Data: UTF8String;
    Max: Integer): 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字符串就是我們想要的結果。

 

♥  呵呵,如果想要用Delphi+iw進行微信開發的,看到這里應該算是有方向了吧,加油!希望早日看到各位的大作。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM