場景:團隊開放微信第三方公眾號,此公眾號中原先有一個活動,按照正常流程公眾號配置指定接收消息事件的url,服務器端指定servlet進行xml解析處理。
現在原先基礎上增加一個活動,此時為開放第三方公眾號,里面有兩個活動暫且稱為A和B,A原先由Fa服務器指定的servlet處理微信推過來的事件(比如說關注事件),A和B有不同的服務器,獨立的項目,不同的數據庫。此時需求是根據場景的不同,將微信推送過來的消息分別放在不同的servlet里面進行解析處理。但實際上微信只往其中一個servlet中進行消息推送。
過程:使用轉發就可以不用考慮了,轉發只能在同一web中的servlet中進行跳轉。如果場景是在同一個tomcat中,那么可以用request.getRequestDispatcher("/xxxx").forward(request,response);
如果消息事件只涉及到消息推送等,也就是只用到了微信推送xml里面的數據,那么上述場景完全可以在同一個servlet中進行處理,處理的方法就是根據不同的場景值。
具體的思路過程就不細說了,大體方向:在微信推送過來xml的時候就把xml給轉到指定的服務器下面的servlet中; 在進入到特定場景的時候把得到的數據轉到知道的服務器下面的servlet中;
結果:測試了各種方法百度了各種方法之后,我這里用了java后端發送post請求:
這里以微信第三方平台開發為例:
微信推送過來的消息為(部分代碼):
1 /** 2 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse 3 * response) 4 */ 5 protected void doPost(HttpServletRequest request, HttpServletResponse response) 6 throws ServletException, IOException { 7 DebugUtils.savaDebugInfo(null, "進入到servlet種的dePost",null); 8 String nonce = request.getParameter("nonce"); 9 String timestamp = request.getParameter("timestamp"); 10 String msgSignature = request.getParameter("msg_signature"); 11 12 request.setCharacterEncoding("UTF-8"); 13 response.setCharacterEncoding("UTF-8"); 14 PrintWriter out = response.getWriter(); 15 String message = "success"; 16 try { 17 StringBuilder sb = new StringBuilder(); 18 BufferedReader in = request.getReader(); 19 String line; 20 while ((line = in.readLine()) != null) { 21 sb.append(line); 22 } 23 String xml = sb.toString();
收到消息后要對xml進行解析,微信官方文檔給的有解析的方法。解析之后根據解析出來的數據判斷不同的場景走不同的出來方法。
現在我要在微信推送過來消息進入doPost方法的時候同時把消息發送到其他指定的服務器下面servlet中去。
首先到指定服務器下,找到WEB-INF下面的xml文件進行servlet訪問配置:
1 <servlet> 2 <servlet-name>OpenWXMessageServlet</servlet-name> 3 <servlet-class> 4 xx.xx.xx.MessageServlet 5 </servlet-class> 6 </servlet> 7 <servlet-mapping> 8 <servlet-name>OpenWXMessageServlet</servlet-name> 9 <url-pattern>/OpenWXMessageServlet</url-pattern> 10 </servlet-mapping>
然后再接收到消息事件讀取到未解密的xml的時候去發送post請求:
1 /** 2 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse 3 * response) 4 */ 5 protected void doPost(HttpServletRequest request, HttpServletResponse response) 6 throws ServletException, IOException { 7 DebugUtils.savaDebugInfo(null, "進入到servlet種的dePost",null); 8 String nonce = request.getParameter("nonce"); 9 String timestamp = request.getParameter("timestamp"); 10 String msgSignature = request.getParameter("msg_signature"); 11 12 request.setCharacterEncoding("UTF-8"); 13 response.setCharacterEncoding("UTF-8"); 14 PrintWriter out = response.getWriter(); 15 String message = "success"; 16 try { 17 StringBuilder sb = new StringBuilder(); 18 BufferedReader in = request.getReader(); 19 String line; 20 while ((line = in.readLine()) != null) { 21 sb.append(line); 22 } 23 String xml = sb.toString(); 24 String path = "http://xxxxxx.com/OpenWXMessageServlet?nonce=" 25 +nonce+"×tamp="+timestamp+"&msg_signature="+msgSignature; 26 String echostr = HttpRequest.sendPost(path, xml);
然后指定服務器接收到的時間戳和隨機數都是再一致狀態下的了。這樣就實現了開始場景的需求。
附帶一下我這邊的sendPost方法:

1 /** 2 * 向指定 URL 發送POST方法的請求 3 * 4 * @param url 5 * 發送請求的 URL 6 * @param param 7 * 請求參數,請求參數應該是 name1=value1&name2=value2 的形式。 8 * @return 所代表遠程資源的響應結果 9 */ 10 public static String sendPost(String url, String param) { 11 return sendPost(url, param, ""); 12 } 13 public static String sendPost(String url, String param, String charset) { 14 PrintWriter out = null; 15 BufferedReader in = null; 16 String result = ""; 17 InterfaceInfo interfaceInfo = new InterfaceInfo(url, param, ""); 18 19 try { 20 URL realUrl = new URL(url); 21 // 打開和URL之間的連接 22 URLConnection conn = realUrl.openConnection(); 23 // 設置通用的請求屬性 24 conn.setConnectTimeout(60000); 25 conn.setReadTimeout(60000); 26 conn.setRequestProperty("accept", "application/Json;" + charset); 27 conn.setRequestProperty("connection", "Keep-Alive"); 28 conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)"); 29 conn.setRequestProperty("Content-Type", "application/Json;charset=UTF-8;"); 30 // 地址接口用到x-auth-header 31 if (param.contains("AddressReq")) { 32 conn.setRequestProperty("X-AUTH-HEADER", "ACAE705AF0531007BDCBC29D5121DBD6"); 33 } 34 // 鉑濤錦江mpls通道必須加驗證 35 if(url.contains("/v1/score/pay")){ 36 conn.setRequestProperty("apigwkey", "d72fa68d5734bb66b4b27d9b5dd50f65"); 37 } 38 // 發送POST請求必須設置如下兩行 39 conn.setDoOutput(true); 40 conn.setDoInput(true); 41 // 獲取URLConnection對象對應的輸出流 42 out = new PrintWriter(conn.getOutputStream()); 43 // 發送請求參數 44 out.print(param); 45 // flush輸出流的緩沖 46 out.flush(); 47 // 定義BufferedReader輸入流來讀取URL的響應 48 in = new BufferedReader(new InputStreamReader(conn.getInputStream())); 49 String line; 50 while ((line = in.readLine()) != null) { 51 result += line; 52 } 53 if (StringUtils.isBlank(result)) { 54 GetServiceUtil.getExceptionLogService().saveDebugInfo("扣分返回", "result等於空字符串"); 55 } 56 // 請求結束更新開始時保存的接口日志 57 String resultInterface = ""; 58 if (result.length() > 1000) { 59 resultInterface = result.substring(0, 1000); 60 } else { 61 resultInterface = result; 62 } 63 interfaceInfo.setRESULT(resultInterface); 64 } catch (Exception e) { 65 interfaceInfo.setRESULT(e.getMessage()); 66 67 ExceptionLog exceptionLog = new ExceptionLog(); 68 exceptionLog.setExceptiontype(ConstantData.EXCEPTION_TYPE_RUNTIME); 69 exceptionLog.setExceptiontitle("Http異常"); 70 exceptionLog.setExceptionmsg(url); 71 if (e.toString().length() > 500) { 72 exceptionLog.setStack(e.toString().substring(0, 500)); 73 } else { 74 exceptionLog.setStack(e.toString()); 75 } 76 ExceptionServiceImpl exceptionService = GetServiceUtil.getExceptionService(); 77 exceptionService.insertExceptionLogInfo(exceptionLog); 78 79 if (e.toString().contains("401")) { 80 result = e.toString(); 81 } else { 82 result = "服務器異常。。"; 83 } 84 } 85 // 使用finally塊來關閉輸出流、輸入流 86 finally { 87 try { 88 GetServiceUtil.getExceptionLogService().saveInterfaceInfo(interfaceInfo); 89 if (out != null) { 90 out.close(); 91 } 92 if (in != null) { 93 in.close(); 94 } 95 } catch (IOException ex) { 96 ex.printStackTrace(); 97 } 98 } 99 return result; 100 }