示例代碼已經放出!請移步使用delphi+intraweb進行微信開發1~4代碼示例進行下載,雖為示例代碼但是是從我項目中移出來的,封裝很完備適於自行擴展和修改。
在第二講使用delphi+intraweb進行微信開發2—intraweb以.net方式發布(以asp.net mvc4模式部署)在IIS(.net虛擬主機)上 我們成功把iw應用部署在了雲虛擬主機上,在這一講里,我們將延續第一講的內容回歸微信開發,這次講解微信消息處理。
首先明確幾個知識點:
1、微信服務器轉發用戶消息使用的http post方法,在第一講中關於微信服務器的http數據提交方法我們並沒有細說,實際上微信進行接入驗證使用的是http get方法;而轉發用戶消息則使用的http post方法,並且轉發消息時消息以xml格式進行編碼,ContentType=text/xml。
2、微信服務器消息轉發是可以選擇三種數據傳遞方式的,一、明文;二、加密;三、混合。在這一講了為了調試方便,我們采用明文方式傳遞數據。下一講再講解消息加密方式的處理。
本來感覺這一講的內容沒什么難度,要是.net、php甚至是delphi的webbroker都應該很容易實現。但是用上iw后發現問題很復雜!
iw處理http請求數據的類是THttpRequest,但是我看遍了THttpRequest的屬性和方法就沒有找到直接存取http content的地方,只有個似乎是讀取http content的THttpRequest.ContentFields屬性,但是實際執行代碼並調試后發現,這個屬性根本無法取到微信服務器傳遞過來的xml文件,內容始終是空的。
經過反復驗證發現這個ContentFields屬性只能對http request時ContentType為application/x-www-form-urlencoded時傳遞的鍵值對內容有效,也就是對於表單類型的提交是可以取到數據的,在第一講的微信接入中就是這種情況,微信傳遞過來的signature、timestamp、nonce等字段值都是可以通過THttpRequest.ContentFields取出來的。
事情發展到現在徹底陷入困境了,那么ContentType=text/xml時如何用THttpRequest類的方法獲取內容呢?經過研究發現THttpRequest類有個Files屬性,當時感覺希望就在這個屬性上,畢竟xml也可以當做文件來上傳不是嗎?呵呵,遺憾的是,我當時無論怎么實驗(反匯編dcu都用上了),這個屬性的文件數始終是0,這個希望也斷了!
於是乎在iw官方的問題貼論壇上發帖留言開始了求教之路,1天、2天始終有人看沒人回,在屢次搜索相關提問后發現了曾經有人和我遇到同樣的問題,當時作者給了回應說提問者表示不清楚要求發電子郵件給作者代碼,呵呵,算是抓到稻草了,立即冒充提問者給作者發送我的代碼並附上了提問,呀呀,石沉大海啊,呵呵,iw真是想愛你這么的不容易。
沒有辦法繼續搜索其他人的提問吧,功夫不負有心人啊,終於找到了一個帖子,里面提問者和我的問題不相同,但是回答者提到iw demos里面有個PostFormData示例工程,立即查看我下載的demo,發現根本沒有這個工程,上官網重新下載例子工程,呵呵,終於有了!打開代碼一看,原來如此!跟第一講一樣就是一行代碼難受我好幾天。
親們看吧:
就是那個“RegisterContentType”方法,呵呵,你能想到嗎?幫助里面有提到嗎?我靠!
好吧,總算可以了,那么接着說,增加了content-type注冊之后,就可以用THttpRequest.Files獲取post過來的xml了,這倒是和我最初的預測差不多,小安慰一下。
親們,我的血淚歷程告訴大家,針對iw這種幫助不完善又沒源代碼的web開發框架,提問區查找和iw demos就是我們最大的依靠了,要用iw就趕緊下載個最新的demo看看吧。
剩下就沒什么好說了,貼個代碼截圖大伙看看,照着微信的文檔做,比較容易:
TEventHandler類:
部署到服務器上后用微信客戶端測試截屏:
如果你看到這里了,好吧,我再告訴你個小秘密吧:
經我反復測試,那個“RegisterContentType”方法只在SA、ISAPI模式下有效,當我按照第二講說的編譯成library並按照aspx模式部署好后,無論如何也取不到xml文件,僅僅是工程類型由於部署要求做了個變化,其它代碼都沒有任何變化,就是不知道是為什么,上圖大伙看到的截圖是我以ISAPI方式部署在我服務器上實現的。
最后再附上微信消息的xml格式中日期字段的編解碼函數,微信的日期類型是整形值,所以需要將整形值轉成TDateTime類型,微信的整形值的計算是以'1970-01-01 00:00:00'作為基准時間計算的秒差。另外需要注意的是,微信時間是UTC時間,也就是轉換成北京時間要加上8個小時。
/// <summary>
/// 微信的日期時間都是int64類型,是和1970-01-01 00:00:00之間的秒差,這個函數用來返回1970-01-01 00:00:00時刻
/// </summary>
/// <returns>1970-01-01 00:00:00</returns>
function GetWxBaseDt: TDateTime;
begin
Result := VarToDateTime('1970-01-01 00:00:00');
end;
/// <summary>
/// 獲取適合微信使用的當前日期,以int64表示,是當前時間和1970-01-01 00:00:00之間的秒差
/// 然后再減去3600*8轉成UTC時間秒差即為微信時間
/// </summary>
/// <returns>當前時間,int64格式</returns>
function GetWxNow: Int64;
begin
Result := SecondsBetween(Now, GetWxBaseDt) - 3600 * 8;
end;
function GetWxNowStr: string;
var
i64: Int64;
begin
i64 := GetWxNow;
Result := IntToStr(i64);
end;
/// <summary>
/// 把微信xml中獲取的CreateTime字段值當做參數傳入函數
/// 即可將微信的int類型的時間轉換成TDatetime類型
/// </summary>
/// <returns>TDateTime</returns>
function ConvertWxDtToDateTime(wxDt: string): TDateTime;
var
i64: Int64;
begin
i64 := StrToInt64(wxDt);
Result := IncSecond(GetWxBaseDt, i64 + 3600*8);
end;