- 1 企業(yè)微信與微信企業(yè)號
- 1.1 什么是企業(yè)微信-企業(yè)微信介紹
- 1.2 企業(yè)號升級到企業(yè)微信的通知
- 1.3 企業(yè)微信的發(fā)布-微信企業(yè)號將作為微信插件
- 1.4 企業(yè)微信與微信企業(yè)號的區(qū)別和聯(lián)系
- 1.5 微信企業(yè)號與服務(wù)號 訂閱號的區(qū)別
- 2 企業(yè)微信使用
- 2.1 申請企業(yè)微信
- 2.2 使用微信插件(原企業(yè)號)
- 2.2.1 在企業(yè)微信中使用微信企業(yè)號
- 2.2.2 修改微信企業(yè)號的LOGO
- 2.2.3 在微信插件底部可快捷打開企業(yè)微信客戶端
- 2.3 修改應(yīng)用的LOGO
- 2.4 企業(yè)微信獲取對方是否已經(jīng)閱讀了信息的狀態(tài)
- 2.5 登錄企業(yè)微信APP
- 2.6 企業(yè)微信退出指定的企業(yè)
- 2.7 企業(yè)微信退出后重新加入企業(yè)
- 2.8 企業(yè)微信后臺添加成員及邀請成員加入
- 2.9 企業(yè)成員幾種加入企業(yè)微信的方法對比
- 2.10 免費的企業(yè)郵箱并在企業(yè)微信中提示收到郵件
- 2.11 企業(yè)微信管理員后臺管理
- 2.11.1 企業(yè)微信成員賬號能夠修改嗎?
- 2.11.2 通訊錄如何添加自定義的字段-擴展屬性-企業(yè)微信
- 2.12 企業(yè)微信內(nèi)部局域網(wǎng)如何訪問企業(yè)微信-網(wǎng)管設(shè)置?
- 3 企業(yè)微信開發(fā)(Access Excel VBA)
- 3.1 企業(yè)微信開發(fā)入門
- 3.2 企業(yè)微信開發(fā)-回調(diào)
- 3.2.1 為什么要使用HTTPS以及國內(nèi)外有哪些免費SSL證書
- 3.2.2 IIS使用阿里免費SSL證書
- 3.2.3 其它環(huán)境使用阿里免費SSL證書
- 3.2.4 企業(yè)微信及微信企業(yè)號開發(fā)經(jīng)驗總結(jié)
- 3.2.5 企業(yè)微信及微信企業(yè)號回調(diào)設(shè)置
- 3.2.6 回調(diào)URL校驗失敗或-40001錯誤或echostr校驗失敗,請您檢查是否正確解密并輸出明文echostr 終極解決方法
- 3.3 企業(yè)微信獨家經(jīng)驗
- 3.4 相關(guān)說明
- 3.4.1 企業(yè)微信主動調(diào)用頻率限制
- 3.4.2 企業(yè)微信開發(fā)全局錯誤碼
- 3.4.3 微信加解密庫下載與錯誤返回碼
- 3.4.4 企業(yè)號的CorpSecret在企業(yè)微信中如何查到
- 4 企業(yè)微信開發(fā)VIP經(jīng)驗心得
回調(diào)URL校驗失敗或-40001錯誤或echostr校驗失敗,請您檢查是否正確解密并輸出明文echostr 終極解決方法
- 2017-08-14 14:03:13
- zstmtony
- 28610
- 最后編輯:zstmtony 于 2017-08-15 14:02:00
回調(diào)URL校驗失敗或-40001錯誤或echostr校驗失敗,請您檢查是否正確解密并輸出明文echostr 終極解決方法
感謝Fans.net的幫助。
主要解決的思路:
1.要借助微信企業(yè)號接口調(diào)試工具: http://qydev.weixin.qq.com/debug
使用工具的好處比自己在代碼中寫結(jié)果日志更好一些,當然,可以把接口調(diào)試工具與打日志結(jié)合起來,效果更佳
此工具旨在幫助開發(fā)者檢測調(diào)用【微信公眾平臺開發(fā)者API】時發(fā)送的請求參數(shù)是否正確,提交相關(guān)信息后可獲得服務(wù)器的驗證結(jié)果
使用說明:
1). 選擇合適的接口。
2). 系統(tǒng)會生成該接口的參數(shù)表,您可以直接在文本框內(nèi)填入對應(yīng)的參數(shù)值。(紅色星號表示該字段必填)
3). 點擊檢查問題按鈕,即可得到相應(yīng)的調(diào)試信息。
我們使用這個方法來調(diào)試
選擇“建立連接”--》”測試回調(diào)模式“
1)選擇接口類型為“建立連接”
2)選擇接口列表為“測試回調(diào)模式”
方法:GET
3)填寫參數(shù)列表
*URL 開發(fā)者填寫URL,調(diào)試時將把消息推送到該URL上 (這個網(wǎng)頁要先在服務(wù)器建立好文件,內(nèi)容可參考這里:
如我填的是: m.mzhfr.cn/Callback.php
*Token:你設(shè)置的Token
*EncodingAESKey:你的EncodingAESKey
*EchoStr:回文,只允許23個字節(jié)的數(shù)字
*ToUserName:企業(yè)號CorpID
再點擊 檢查問題 按鈕
企業(yè)微信會要求你填寫應(yīng)用的URL、Token、EncodingAESKey三個參數(shù),驗證URL、Token,加密的詳細處理請參考接收消息時的加解密處理章節(jié)。
URL是企業(yè)應(yīng)用接收企業(yè)微信推送請求的訪問協(xié)議和地址,支持http或https協(xié)議。
Token可由企業(yè)任意填寫,用于生成簽名。
EncodingAESKey用于消息體的加密,是AES密鑰的Base64編碼。
2. 你可將 EchoStr 設(shè)置為:123456789 (先簡單 方便測試)
3. 在服務(wù)器的Callback.php 文件中先做一個 直接寫死的回傳值,如代碼如下:
<?php echo "123456789"; ?>4. 點擊 檢查問題 按鈕 看看有什么錯誤提示,如果返回是你指定的 123456789 的正確字符,那就正常,如果不是,根據(jù)相應(yīng)的錯誤提示去處理
如一般最多的錯誤是 這個:提示 {"errcode":70002,"errmsg":"echostr校驗失敗,請您檢查是否正確解密并輸出明文echostr "}
有時也會返回 -40001 的錯誤 -40001 簽名驗證錯誤 (加解密錯誤返回值),也是下面的原因引起的。
以下是在服務(wù)器的callback.php 將相關(guān)參數(shù)寫到日志文件的結(jié)果:
sVerifyMsgSig: 21494885**********96f7c050c sVerifyTimeStamp: 15*******9020 sVerifyNonce: 7*******574 sVerifyEchoStr: 5/wnXwID******************yyt3Oj1vQQGZTB5NVIVyMm4zdWUE3wXt5ejsqiGZ9b8t8vGkx9H VvA== errCode: -40001
這種可能有多個原因
1)是你 Callback.php 的文件沒有返回值 ,你可以在 IE里直接打開 m.mzhfr.cn/Callback.php
看看返回的值 是否 是123456789 ,如果沒有返回,那就找服務(wù)器或PHP有否正確解析
2)IE里直接打開 m.mzhfr.cn/Callback.php 返回的值是正確的,但企業(yè)號調(diào)試工具總是提示
{"errcode":70002,"errmsg":"echostr校驗失敗,請您檢查是否正確解密并輸出明文echostr "}
這個是很多網(wǎng)友遇到問題最多的一種情況
一般可能是 :您的PHP文件應(yīng)該對echostr參數(shù)解密并原樣返回echostr明文(不能加引號,不能帶bom頭,不能帶換行符),則接入驗證生效,接收消息才能開啟。
如果你的echostr明文,帶有引號,或帶有換行符,或帶有Bom頭,則判斷為不相同,其它帶Bom頭這種情況是遇到最多的情況,但很多人判斷不出來
因為直接在IE中打開 網(wǎng)頁,返回的值看起來是正常的。是123456789, 但實際上在用如抓包軟件工具二進制方式(如Fiddler中的Composer) 使用拼接出來的 網(wǎng)址打開
(拼接起來的網(wǎng)址:https://wx.office-cn.net/example/callback_valid.php?msg_signature=1**************0b0b2a8af2×tamp=1501724483&nonce=4182954&echostr=Sau/3******2dIR76Ajomsv/f6DJbNDv******IJStyTh9AQEjsKG45jvZEoIEYvvlz1wGh91JFIitK21Q==
可看到是有不同的
錯誤的值:在123456789前面 會帶有 幾個亂碼符號
正確的返回值應(yīng)該是這樣的:
解決辦法:1)可將PHP網(wǎng)頁文件另存為ansi ,一般都可以解決,但這種方法不是最理想的辦法
2)用sublime 或notpad++打開你的回調(diào)PHP文件,點擊編碼按鈕,將文件的編碼改為無BOM頭后保存(可保存編碼 改為 UTF-8那種 無bom頭)
(這個問題我弄了2天,才解決,希望這個經(jīng)驗讓您少走很多彎路)
3) 如果 http 連接正常,而 https 連接超時,則很可能是你的https 有問題,或證書有問題,要換不同的地區(qū) 直接訪問這個網(wǎng)址看看行不行
我遇到過很奇怪的現(xiàn)象,企業(yè)微信測試工具 訪問不到我的https, 而有些朋友 的電腦可以訪問,有些不能訪問。
用企業(yè)微信測試網(wǎng)頁 檢查問題,提示:
建立連接:測試回調(diào)模式
請求地址: https://*******/callback_valid.php
返回結(jié)果: {"errcode":70001,"errmsg":"連接超時"} 錯誤號是 70001 連接超時。解決辦法是先解決https可以正常直接訪問,
所以一定要先保證這個https://m.mzhfr.cn/Callback.php 網(wǎng)址可直接打開
如果 SSL證書沒有問題,其它也正常,但經(jīng)常出現(xiàn)https訪問不到的話,如果你使用的是阿里云的免費SSL證書,可以使用他們提供的修復工具執(zhí)行一下,并重啟服務(wù)器
阿里的免費SSL證書服務(wù)器設(shè)置工具ITrusIIS(感謝fans提供):在這篇文章的最下面有下載鏈接
ITrusIIS設(shè)置界面如下:
選擇 最佳配置,然后點應(yīng)用 即可,可解決很多https 有時訪問不到的問題
(如果 客戶端的瀏覽器 是Google谷歌的瀏覽器 53 54版本有問題 要升級到55 56)
另也確保你服務(wù)器的安全軟件(如安全狗)有否攔截443 https的端口。
我的其它一臺服務(wù)器就是安全軟件設(shè)置了 將443 TCP端口 一律攔截屏蔽導致的(我開放的白名單IP可以訪問,但別人的網(wǎng)絡(luò)就訪問不了)
導致微信企業(yè)號測試工具一直返回錯誤:
建立連接:測試回調(diào)模式
請求地址: https://www.****.com/callback_valid.php
返回結(jié)果: {"errcode":70001,"errmsg":"連接超時"}
只要在安全軟件中設(shè)置 開放這個端口就可以了
如果您使用的是Windows自帶的防火墻,入口規(guī)則也需要將443開放即可。
另如果https打不開,可以逐級來檢查問題,先檢查網(wǎng)站服務(wù)器的443端口是否打開,可使用Telnet命令或Tcping 第三方工具
telnet和ping是我們最經(jīng)常使用的兩個命令。但ping只是一個通信協(xié)議,是ip協(xié)議的一部分,tcp/ip 協(xié)議的一部分,Ping 在Windows系下是自帶的一個可執(zhí)行命令。而Telnet服務(wù)雖然也屬于客戶機/服務(wù)器模型的服務(wù),但它更大的意義在于實現(xiàn)了基于Telnet協(xié)議的遠程登錄,但win7 win10 的telnet服務(wù)是默認關(guān)閉的,要打開 它,在控制面板里,執(zhí)行“程序”—“打開或關(guān)閉Windows功能” 選擇Telnet客戶端 ,開啟即可,然后在命令行就可使用它了
也可使用Tcping第三方工具,或使用 http://tool.chinaz.com/port/ 來檢查指定網(wǎng)站指定端口是否開放了
Tcping工具下載:https://elifulkerson.com/projects/tcping.php
4) 特別注意 在消息API 接收消息服務(wù)器配置及 企業(yè)微信調(diào)試網(wǎng)頁里,填寫的URL 網(wǎng)址后面一定不要有空格 或其它字符,有時明明所有都對了,就是不小心在網(wǎng)址最后 多了一個空格,總是校驗通不過
下圖的URL 網(wǎng)址最后就是多了一個空格,導致總提示 回調(diào)URL校驗失敗
5.然后再將這個寫死的Callback.php 文件的內(nèi)容改成 官方提供的php.zip的sample.php 的內(nèi)容,就是用代碼根據(jù)你提供的參數(shù)真正返回明文
注意相關(guān)參數(shù)改成你自己的
<?php include_once "WXBizMsgCrypt.php"; // 假設(shè)企業(yè)號在公眾平臺上設(shè)置的參數(shù)如下 $encodingAesKey = "jWmYm7qr5nMoAUwZRjGtBxmz3KA1tkAj3ykkR6q2B2C"; $token = "QDG6eK"; $corpId = "wx***********6c7"; /* ------------使用示例一:驗證回調(diào)URL--------------- *企業(yè)開啟回調(diào)模式時,企業(yè)號會向驗證url發(fā)送一個get請求 假設(shè)點擊驗證時,企業(yè)收到類似請求: * GET /cgi-bin/wxpush?msg_signature=5c45ff5e21c57e6ad56bac8758b79b1d9ac89fd3×tamp=1409659589&nonce=263014780&echostr=P9nAzCzyDtyTWESHep1vC5X9xho%2FqYX3Zpb4yKa9SKld1DsH3Iyt3tP3zNdtp%2B4RPcs8TgAE7OaBO%2BFZXvnaqQ%3D%3D * HTTP/1.1 Host: qy.weixin.qq.com 接收到該請求時,企業(yè)應(yīng) 1.解析出Get請求的參數(shù),包括消息體簽名(msg_signature),時間戳(timestamp),隨機數(shù)字串(nonce)以及公眾平臺推送過來的隨機加密字符串(echostr), 這一步注意作URL解碼。 2.驗證消息體簽名的正確性 3. 解密出echostr原文,將原文當作Get請求的response,返回給公眾平臺 第2,3步可以用公眾平臺提供的庫函數(shù)VerifyURL來實現(xiàn)。 */ // $sVerifyMsgSig = HttpUtils.ParseUrl("msg_signature"); $sVerifyMsgSig = "5c45ff5e21c57e6ad56bac8758b79b1d9ac89fd3"; // $sVerifyTimeStamp = HttpUtils.ParseUrl("timestamp"); $sVerifyTimeStamp = "1409659589"; // $sVerifyNonce = HttpUtils.ParseUrl("nonce"); $sVerifyNonce = "263014780"; // $sVerifyEchoStr = HttpUtils.ParseUrl("echostr"); $sVerifyEchoStr = "P9nAzCzyDtyTWESHep1vC5X9xho/qYX3Zpb4yKa9SKld1DsH3Iyt3tP3zNdtp+4RPcs8TgAE7OaBO+FZXvnaqQ=="; // 需要返回的明文 $sEchoStr = ""; $wxcpt = new WXBizMsgCrypt($token, $encodingAesKey, $corpId); $errCode = $wxcpt->VerifyURL($sVerifyMsgSig, $sVerifyTimeStamp, $sVerifyNonce, $sVerifyEchoStr, $sEchoStr); if ($errCode == 0) { // // 驗證URL成功,將sEchoStr返回 // HttpUtils.SetResponce($sEchoStr); } else { print("ERR: " . $errCode . "\n\n"); }
6.正常如果第4步是正確的,第5步就沒有什么問題。如果有問題,可以將傳遞過來的參數(shù)或計算的中間值寫到一個文件文件中作為日志來調(diào)試
如在里面加一些寫到日志文件的代碼 ,這些代碼讓我很快就發(fā)現(xiàn)了問題所在。節(jié)約了大量的調(diào)試時間:
$myfile = fopen("日志文件.txt", "w") or die("Unable to open file!"); fwrite($myfile, "sVerifyMsgSig: " .$sVerifyMsgSig . "\r\n" ); fwrite($myfile, "sVerifyTimeStamp: " .$sVerifyTimeStamp . "\r\n" ); fwrite($myfile, "sVerifyNonce: " .$sVerifyNonce. "\r\n" ); fwrite($myfile, "sVerifyEchoStr: " .$sVerifyEchoStr . "\r\n" ); fwrite($myfile, "errCode: " .$errCode . "\r\n" ); fwrite($myfile, "sEchoStr: " .$sEchoStr . "\r\n" ); fwrite($myfile, "sEchoStr: " .strlen($sEchoStr) . "\r\n" ); fclose($myfile);
如果 還是出錯,可以將這些日志文件里獲取的參數(shù),再拼接成一個URL 直接在網(wǎng)址中 執(zhí)行看看返回的值對不對
如我的拼接成這樣:
http://m.mzhfr.cn/callback.php?msg_signature=5c06f07ec8745da8c550ec54e0f503b9084752f0×tamp=1502547531&nonce=209465957&echostr=Wd/nvLNvMCOpcWN6HO5NM99HP3eeUCSWGXmZnO5KFCCNIvMUuvjLwmtxzcpffQYh1Gp7tjljidXd9WJkbIosOw==
7.測試OK后,再打開企業(yè)應(yīng)用,自建應(yīng)用里,你的應(yīng)用,接收消息,API接收
啟用API接收,然后設(shè)置 接收消息服務(wù)器配置
保存即可,一般是成功的了,如果還是提示 回調(diào)URL校驗失敗,則按上面的步驟再逐個排查
經(jīng)驗總結(jié):
1. 檢查返回的echostr有沒有被加上換行符?
2. 檢查返回的echostr有沒有被加上html標簽?
3. 檢查返回的echostr有沒有被加上不可見的字符?
4. 檢查返回的echostr有沒有被加上引號?
5. php開發(fā)者還需要檢查返回的echostr有沒有帶上bom頭?
6. 如果 sVerifyEchoStr: bCLSV************T6GilQRmCW wli1RYIjpH3uDhRsALel3/Fbme4pQiBLHwOadrB9QCsF86o3J8bY4Q==
中間內(nèi)容有空格,則解密的明文 不正確且顯示 -40001 錯誤,如果中間內(nèi)容沒有空格,則解密的明文是正確的
解決:這個參數(shù)不要使用UrlDecode解密。使用URL轉(zhuǎn)碼反而不行
7. HTTP ERROR 500
說明網(wǎng)址本身代碼或引用的文件丟失。先直接打開這個網(wǎng)址看看是否正確
8. 有一種情況明明用 寫日志文件方式發(fā)現(xiàn)返回的明文是123456789 是正確的,但還是會提示這個錯誤:
{"errcode":70002,"errmsg":"echostr校驗失敗,請您檢查是否正確解密并輸出明文echostr "}
原來是因為 callback_valid.php 調(diào)用了 helper.php文件,而我在helper.php文件的以下代碼中為測試加一 print 的代碼
結(jié)果就導致 整個 callback_valid.php 會輸入 print("config: " . get_php_file("../config.php") . "\n\n"); 再加真正的返回值 123456789
這樣就導致 與實際要求的值 123456789 不相等。 只要把這個函數(shù)中測試的 Print代碼注釋掉就可以了。
function loadConfig(){
print("config: " . get_php_file("../config.php") . "\n\n");
return json_decode(get_php_file("../config.php"));
}
9. 為保證 https://www.test.com/callback.php?msg_signature=5c45ff5e21c57e6ad56bac8758b79b1d9ac89fd3×tamp=1409659589&nonce=263014780&echostr=P9nAzCzyDtyTWESHep1vC5X9xho%2FqYX3Zpb4yKa9SKld1DsH3Iyt3tP3zNdtp%2B4RPcs8TgAE7OaBO%2BFZXvnaqQ
可將 http://qydev.weixin.qq.com/debug 里的 EchoStr 設(shè)置為很短:如123
盡量避免 &echostr= 這個參數(shù)里 沒有空格 或 + 符號。否則不好用直接打開網(wǎng)址的方式來測試,會返回-40001錯誤
10.重點
1.要注意將PHP另存為無BOM頭的UTF-8格式
2 是 EchoStr參數(shù)獲取不要加 urldecode轉(zhuǎn)換 (要命的是官方提供的示例就加了url轉(zhuǎn)換,所以出錯)
即改成 $sVerifyEchoStr = $_GET["echostr"]; //$sVerifyEchoStr = urldecode($_GET["echostr"]);
3.注意URL網(wǎng)址 后面不能有空格
4.注意 PHP網(wǎng)頁中 前面調(diào)試 OK后,到最后一步時,要把前面所有的 echo 或 print 代碼去掉,否則即使最后的 echo $sEchoStr 是正確的
但因為前面有一些 調(diào)試的代碼: echo "取得token成功" , 結(jié)果 總的返回值 為 取得token成功 及 $sEchoStr 從而企業(yè)微信判斷明文不符,所以在最后一步調(diào)試時,要將前面所有調(diào)試的echo 代碼注釋 掉或刪除
另也可嘗試其它一些經(jīng)驗:
1.應(yīng)該返回整形echo (int)$sEchoStr,非字符串型。
另外,其他文件errorCode.php, pkcs7Encoder.php, sha1.php, xmlparse.php,不要去修改2.第一次解決是另存為ANSI格式,但不太理想,因為有時還是要用UTF8
現(xiàn)在找到原因后改成成無bom的UTF8格式就可以了
3.在返回結(jié)果前,加上 header("Content-Type:text/html; charset=utf-8");
header("Content-Type:text/html; charset=utf-8");
echo $sEchoStr;
4.mcrypt沒裝對,mcrypt沒加載的話解密一定出錯,echostr自然也算不出. 最好下載并使用官方最新的加解密庫。
5. 問題已經(jīng)解決。錯誤原因是我在request參數(shù)時,聽網(wǎng)上例子,加了urldecode,直接去掉即可。
附加代碼如下:
int ret = 0;
string sReqMsgSig = context.Request.QueryString["msg_signature"];
string sReqTimeStamp = context.Request.QueryString["timestamp"];
string sReqNonce = context.Request.QueryString["nonce"];
// 獲取Post請求的密文數(shù)據(jù)
StreamReader reader = new StreamReader(context.Request.InputStream, Encoding.GetEncoding("UTF-8"));
string sReqData = reader.ReadToEnd();
reader.Close();
string sMsg = ""; // 解析之后的明文
ret = wxcpt.DecryptMsg(sReqMsgSig, sReqTimeStamp, sReqNonce, sReqData, ref sMsg);
6. 使用接口EchoStr字符不要超過23個,超過了就會echostr校驗失敗。
如果是新浪云SAE:
1.你用的是SAE的服務(wù)器嗎?是否實名審核通過。
2.下載的微信接口代碼有問題(我從官網(wǎng)下載的代碼就一直驗證失敗,換了一個就好了)。
3.在輸出 $echoStr之前加上header('content-type:text');
另附件fans.net asp.net 相關(guān)的 代碼
public class CheckSignature { public static bool Check(string token, string sVerifyMsgSig, string sVerifyTimeStamp, string sVerifyNonce, string corpId, string encodingAESKey, string echostr, ref string retEchostr) { WXBizMsgCrypt wxcpt = new WXBizMsgCrypt(token, encodingAESKey, corpId); int result = wxcpt.VerifyURL(sVerifyMsgSig, sVerifyTimeStamp, sVerifyNonce, echostr, ref retEchostr); if (result != 0) { System.Console.WriteLine("ERR: VerifyURL fail, ret: " + result); return false; } return true; //ret==0表示驗證成功,retEchostr參數(shù)表示明文,用戶需要將retEchostr作為get請求的返回參數(shù),返回給企業(yè)號。 // HttpUtils.SetResponse(retEchostr); } public static bool DecryptMsg(string token, string encodingAESKey, string corpId, string sReqMsgSig, string sReqTimeStamp, string sReqNonce, string sReqData, ref string sMsg) { int ret = 0; WXBizMsgCrypt wxcpt = new WXBizMsgCrypt(token, encodingAESKey, corpId); ret = wxcpt.DecryptMsg(sReqMsgSig, sReqTimeStamp, sReqNonce, sReqData, ref sMsg); if (ret != 0) { System.Console.WriteLine("ERR: Decrypt Fail, ret: " + ret); return false; } return true; } }
- ITrusIIS.zip 1485MD5