首先我們要明確開發模式什么可以做,什么不可以做:
一、開發模式可以實現的功能
1、可以接收用戶發送過來的消息,通過你自己開發的系統把對應內容反饋回去。
2、可以接收用戶發送過來的地理位置,通過地理位置你可以反饋附近餐廳信息或交通信息(例如高德地圖)
3、通過事件推送,可以識別用戶對公眾帳號訂閱和取消訂閱操作的情況。
4、開發模式的接口除了可以反饋圖文消息,也可以反饋音頻內容給用戶。
5、可以通過通用接口上傳圖片、語音、視頻等內容到公眾平臺上,并且可以調用這些素材。
6、可以管理自定義菜單功能。(該功能還在內測中)
二、開發模式不能實現的功能
1、不能識別用戶賬號名稱,只能識別一串很長的ToUserName,這應該是微信公眾平臺對用戶信息的隱私保護。所以想把用戶拉到自己平臺進行管理這是不可能的。
2、不能管理用戶或查看用戶的個人資料。
3、不能單獨給某一用戶回復消息,這個只能在微信公眾平臺上管理。
4、開發模式不支持消息群發,這個也只能在微信公眾平臺上操作。
目前開發模式主要應用的方式:
1、微信其實是一個瀏覽器,只要你設計制作HTML5的手機頁面,就可以通過微信直接訪問,這樣可以帶給我們無限的想象空間。招商銀行的微信就 是通過這樣的方式實現查詢余額、手機還款等功能。中國聯通的微信可以查話費、查流量等等功能。當然基于這種方式我們還可以做更多的后端功能開發。
2、微信內置的地圖定位,可以實現附近交通情況、查附件餐廳酒店等信息。
3、可以用來做微信聊天機器人,這個需要很強大的語義識別技術,這個功能很多平臺都已經實現。
4、可以通過微信買彩票,例如騰訊官方的“便民彩票”一樣。
5、狀態通知功能,如果用過DNSPOD微信的朋友應該知道,他有個狀態通知功能,當網站DOWN機或帳號登錄,都會自動向你通報。如果這個功能得到普及,以后網站認證不需要短信了。
整體概括起來有兩點 :
1).微信公眾平臺提供了一種網址接入的方法, 這種方法讓我們把公眾賬號服務器地址提交給微信后臺 ;
2).微信在向我們的公眾賬號服務器發送數據的時候會帶一個加密串, 這個加密串只有我們能解密, 同時也只有微信后臺能生成這個加密串。
準備的資料:
1)服務器。首先我們至少要有一臺自己的服務器, 并且這臺服務器要能提供服務, 就是說要能夠被微信后臺的服務器訪問到。
2)外網的ip。這需要服務器有一個外網 IP。
3)端口需要時80的。 Web Server 監聽外網 IP 的 80 端口之后就能收到微信后臺的請求了。
注意 可能很多讀者希望能在自己的 PC 機上做接入的測試, 但是筆者建議不要這么做, 因為這可能會遇到很多的麻煩。 如果你的確想這么做, 請注意以下事情:1) 一般學校宿舍都是使用內網 IP 的, 如果你是住在學校宿舍, 直接放棄吧。2) 家里路由器一般是通過 NAT 的方式工作的, 所以如果你的 PC 機是通過路由器上網的話分配到的也是一個內網 IP, 不能對外提供服務。 這個時候可嘗試把路由器的接入網線直接插到電腦上來獲取外網 IP 聯網。3) 如果第 2 步嘗試失敗(驗證方法 : 在其他電腦上通過瀏覽器訪問你本地 WebServer), 請聯系你的網絡服務提供商(電信、 聯通、 鐵通、 長城寬帶、 天威寬帶等), 詢問他們提供給你的 IP 是否做了 NAT 轉發, 如果是, 則可在允許的情況下要求他們給你一個不做 NAT 轉發的 IP。4) 如果完成第 3 步還未能成功, 那么你和筆者的遭遇是一樣的。 筆者確認了很多次, 確定自己的本地 Web Server 配置是沒有問題的, 然后打電話給網絡提供商,他們并沒有給一個合理的回答, 畢竟他們很少遇到這么做的用戶。 筆者猜測他們可能為了安全, 阻擋了所有的對他們家庭用戶 IP 的主動連接。 那怎么解決這個問題呢? 筆者建議讀者購買一個 linux 的網絡主機, 最好是可以直接登錄的, 而不是那種準備好了環境, 只提供上傳代碼功能的網絡空間。 筆者購買了阿里云的服務器和 MySQL 實例, 用起來還是很不錯的, 而且阿里云的服務也很好。
另外一個問題, 為什么要綁定 80 端口? 公網的環境非常復雜, 我們的公眾賬號服務器和微信后臺的數據傳輸要經過很多的路由器, 這些路由器都有各自的安全設置, 其中有一些會把所有的非 80 端口的包直接丟棄。 如果我們使用非 80 端口就會出現我們發給微信后臺的包對方收不到的情況。 反過來也是一樣的
首先登錄我們自己的公眾賬號的前臺(http://mp.weixin.QQ.com/), 接著依次單擊導航上的“ 高級功能” →右邊的“ 開發模式” →“ 成為開發者”。
服務器的配置:

幾個字段的解釋:可以參考官網解答。官方開發文檔
第一步:填寫服務器配置登錄微信公眾平臺官網后,在公眾平臺后臺管理頁面 - 開發者中心頁,點擊“修改配置”按鈕,填寫服務器地址(URL)、Token和EncodingAESKey。
URL:開發者用來接收微信消息和事件 的接口URL。URL指的是能夠接收處理微信服務器發送的GET/POST請求的地址,并且是已經存在的,現在就能夠在瀏覽器訪問到的地址,這就要求我們先把公眾帳號后臺處理程序開發好(至少應該完成了對GET請求的處理)并部署在公網服務器上。
Token:可由開發者可以任意填寫,用作生成簽名(該Token會和接口URL中包含的Token進行比對,從而驗證安全性);Token 是一個任意的字符串, 你提交 Token 給微信后臺之后, 只有你和微信后臺知道這個字符串是什么, 也就是只有微信后臺和我們的公眾賬號服務器知道這個字符串。 于是 Token 就成了這兩臺服務器之間的密鑰, 它可以讓公眾賬號服務器確認請求是來自微信后臺還是惡意的第三方。
EncodingAESKey:開發者手動填寫或隨機生成,將用作消息體加解密密鑰。
開發者可選擇消息加解密方式:明文模式、兼容模式和安全模式。
第二步:驗證服務器地址的有效性1) 微信后臺在發送數據給公眾賬號服務器的時候, 會額外帶上 3 個參數 :signature、 timestamp、 nonce。 其中 timestamp 是 時 間 戳、 nonce 是 一 個 隨 機 數、signature 是對 timestamp、 nonce 和 Token 進行 SHA1 加密后的字符串。 SHA1 的加密過程是不可逆的, 即不能通過 signature、 timestamp 和 nonce 計算出 Token 是什么。2) 在公眾賬號服務器收到 timestamp、 nonce 和 signature 之后, 同樣對 nonce、timestamp 和 Token 使用 SHA1 加密算法, 得到自己的簽名, 如果自己的簽名和請求中的 signatrue 是一樣的, 那么說明請求是來自微信后臺而不是惡意第三方。
---------------------------------------------------
注意 惡意的第三方有可能會截獲到微信后臺發過來的 signature、 timestamp 和nonce 三個參數, 然后直接用這個三個參數來對公眾賬號服務器發起請求。 按照上面的邏輯是無法判斷的出這是個惡意的請求。 這種攻擊稱為“ replay 攻擊”。 這種攻擊方式的防御方法很簡單 : 加上對 timestamp 的校驗。 收到請求之后, 我們將請求包中的 timestamp 和當前時間比較, 如果誤差大于一定的值就可以認為這個請求是惡意的。 這里不能做相等的比較, 因為數據在網絡上傳輸需要時間, 同時各個服務的本地時間也是有一些差異的。
---------------------------------------------------
開發者提交信息后,微信服務器將發送GET請求到填寫的服務器地址URL上,GET請求攜帶四個參數:
| 參數 | 描述 |
|---|---|
| signature | 微信加密簽名,signature結合了開發者填寫的token參數和請求中的timestamp參數、nonce參數。 |
| timestamp | 時間戳 |
| nonce | 隨機數 |
| echostr | 隨機字符串 |
開發者通過檢驗signature對請求進行校驗(下面有校驗方式)。若確認此次GET請求來自微信服務器,請原樣返回echostr參數內容,則接入生效,成為開發者成功,否則接入失敗。
我們寫一個CoreServlet 類來接收微信服務器傳來的幾個參數:
package com.souvc.weixin.servlet;import java.io.IOException;import java.io.PRintWriter;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import com.souvc.weixin.util.SignUtil;/** * * @ClassName: CoreServlet * @Description: * @author: souvc * @date Jun 15, 2015 11:25:36 AM */public class CoreServlet extends HttpServlet { private static final long serialVersionUID = 4440739483644821986L; /** * 確認請求來自微信服務器 */ public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 微信加密簽名 String signature = request.getParameter("signature"); // 時間戳 String timestamp = request.getParameter("timestamp"); // 隨機數 String nonce = request.getParameter("nonce"); // 隨機字符串 String echostr = request.getParameter("echostr"); PrintWriter out = response.getWriter(); // 通過檢驗signature對請求進行校驗,若校驗成功則原樣返回echostr,表示接入成功,否則接入失敗 if (SignUtil.checkSignature(signature, timestamp, nonce)) { out.print(echostr); } out.close(); out = null; } /** * 處理微信服務器發來的消息 */ public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO 消息的接收、處理、響應 }}
然后需要寫一個驗證微信服務器傳過來的token跟服務器設置的是否一致。
加密/校驗流程如下:1. 將token、timestamp、nonce三個參數進行字典序排序2. 將三個參數字符串拼接成一個字符串進行sha1加密3. 開發者獲得加密后的字符串可與signature對比,標識該請求來源于微信
我們把它封裝成一個工具類 SignUtil :
package com.souvc.weixin.util;import java.security.MessageDigest;import java.security.NoSuchAlgorithmException;import java.util.Arrays;/** * * @ClassName: SignUtil * @Description: * @author: souvc * @date Jun 15, 2015 11:25:18 AM */public class SignUtil { // 與接口配置信息中的Token要一致 private static String token = "souvcweixin"; /** * 驗證簽名 * * @param signature * @param timestamp * @param nonce * @return */ public static boolean checkSignature(String signature, String timestamp, String nonce) { String[] arr = new String[] { token, timestamp, nonce }; // 將token、timestamp、nonce三個參數進行字典序排序 Arrays.sort(arr); StringBuilder content = new StringBuilder(); for (int i = 0; i < arr.length; i++) { content.append(arr[i]); } MessageDigest md = null; String tmpStr = null; try { md = MessageDigest.getInstance("SHA-1"); // 將三個參數字符串拼接成一個字符串進行sha1加密 byte[] digest = md.digest(content.toString().getBytes()); tmpStr = byteToStr(digest); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } content = null; // 將sha1加密后的字符串可與signature對比,標識該請求來源于微信 return tmpStr != null ? tmpStr.equals(signature.toUpperCase()) : false; } /** * 將字節數組轉換為十六進制字符串 * * @param byteArray * @return */ private static String byteToStr(byte[] byteArray) { String strDigest = ""; for (int i = 0; i < byteArray.length; i++) { strDigest += byteToHexStr(byteArray[i]); } return strDigest; } /** * 將字節轉換為十六進制字符串 * * @param mByte * @return */ private static String byteToHexStr(byte mByte) { char[] Digit = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; char[] tempArr = new char[2]; tempArr[0] = Digit[(mByte >>> 4) & 0X0F]; tempArr[1] = Digit[mByte & 0X0F]; String s = new String(tempArr); return s; }}配置一下訪問路徑的 web.xml
<?xml version="1.0" encoding="UTF-8"?><web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <servlet> <servlet-name>coreServlet</servlet-name> <servlet-class> com.souvc.weixin.servlet.CoreServlet </servlet-class> </servlet> <!-- url-pattern中配置的/coreServlet用于指定該Servlet的訪問路徑 --> <servlet-mapping> <servlet-name>coreServlet</servlet-name> <url-pattern>/coreServlet</url-pattern> </servlet-mapping> <!-- 配置400,404,500異常處理 --> <error-page> <error-code>400</error-code> <location>/error/404.jsp</location> </error-page> <error-page> <error-code>404</error-code> <location>/error/404.jsp</location> </error-page> <error-page> <error-code>405</error-code> <location>/error/404.jsp</location> </error-page> <error-page> <error-code>500</error-code> <location>/error/404.jsp</location> </error-page> <error-page> <error-code>505</error-code> <location>/error/404.jsp</location> </error-page> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list></web-app>
部署到公網的服務器上面。
注意如果直接訪問這個地址(http://souvc.com/coreServlet)的話,是會報錯誤的,因為我們這樣訪問沒有傳參數過去,會報500的錯誤。
我們需要通過微信服務器里面的配置來進行。
把這個代碼打包上傳到sae,bae,ace,或是自己的公網服務器即可進行訪問,然后進行驗證。
第三步:依據接口文檔實現業務邏輯后面接上。
源碼分享:
http://yunpan.cn/cQyyUMFWqkiR4 訪問密碼 ffd8
|
新聞熱點
疑難解答