關於微信觸發2次請求的問題【已解決】【原】


關於微信觸發2次請求的問題  [終極方案請直接點此跳轉]

現象描述

測試組在測試環境驗證問題的時候,發現在手機微信頁面點擊某個按鈕,卻觸發了2次ajax請求.
於是開發組小伙伴在修正這個bug的過程中, 一會懷疑前端js問題, 一會又懷疑后端java代碼問題, 卻沒考慮到網絡鏈路轉發機制的問題.
后來筆者提議不改前台,只改后台,注釋全部業務代碼,改成讓線程直接睡眠 Thread.currentThread(N * 1000 ) , 動態修改N參數來模擬業務時間, 發現 sleep 10s以下的請求只會觸發一次, 當sleep 10s以上時,請求會無緣無故觸發2次.

於是有了如下猜想

微信在請求其它服務器時, 如果目標服務器需要10秒以上才能響應,那么微信會自動再次觸發相同請求. 時序圖如下:

 

我的現象

於是開始驗證, 找各種機型和APP試驗,得出下表:

類型 客戶端 請求類型 服務端 服務端 Sleep 秒數 服務端收到請求次數 補充說明
手機android 微信 post 阿里雲ECS主機 2 1次  
手機android 微信 post 阿里雲ECS主機 18 2次  
手機android qq瀏覽器 post 阿里雲ECS主機 2 1次  
手機android qq瀏覽器 post 阿里雲ECS主機 18 2次  
手機android uc瀏覽器 post 阿里雲ECS主機 2 1次  
手機android uc瀏覽器 post 阿里雲ECS主機 18 1次  
手機android 傲游瀏覽器 post 阿里雲ECS主機 2 1次   
手機android 傲游瀏覽器  post 阿里雲ECS主機 18 1次  
蘋果iphone 微信 post 阿里雲ECS主機 2 1次  
蘋果iphone 微信 post 阿里雲ECS主機 18 1次   
蘋果iphone qq瀏覽器 post 阿里雲ECS主機     未試驗
蘋果iphone qq瀏覽器 post 阿里雲ECS主機     未試驗
蘋果iphone uc瀏覽器 post 阿里雲ECS主機     未試驗
蘋果iphone uc瀏覽器 post 阿里雲ECS主機     未試驗
聯想/華碩筆記本PC 微信 post 阿里雲ECS主機 2 1次  
聯想/華碩筆記本PC 微信 post 阿里雲ECS主機 18 1次  
聯想/華碩筆記本PC qq瀏覽器 post 阿里雲ECS主機 2 1次  
聯想/華碩筆記本PC qq瀏覽器 post 阿里雲ECS主機 18 1次  
聯想/華碩筆記本PC 傲游瀏覽器 post 阿里雲ECS主機 2 1次  
聯想/華碩筆記本PC 傲游瀏覽器 post 阿里雲ECS主機 18 1次  

最終得出結論為: android手機端通過微信或手機QQ瀏覽器 ,  用ajax觸發post請求, 調用任意目標服務器,如果服務器業務處理需要10秒以上才能響應, 會導致騰訊(微信服務器)自動再次觸發相同請求. 

普通方案

在請求地址后追加 &connect_redirect=1 即可讓請求不再重發.

怎么找到?非常感謝下鏈接中的9樓, 真是茫茫人海 , 眼前一亮 , 微信開放破平台都沒提及該問題, 真是蛋疼.

微信公眾號網頁授權時,回調兩次?--https://developers.weixin.qq.com/blogdetail?action=get_post_info&lang=zh_CN&token=&docid=b8f9f09573e92ffb0e23308d54bcdcf7

而在第二頁中還有人提及"加&connect_redirect=1 可以解決80%左右,但極小部分android手機加上后仍舊無效"的說法, 但在筆者目前的自測用例中尚未發生 , 忽略不計了.

如何自測

筆者在阿里雲一台ECS服務器, 很早前就專門搭建了一個網頁版的接口對接工具,地址為http://www.kingtool.top/kingtool (注ECS服務器2018年12月底到期)

延遲返回接口地址: http://www.kingtool.top/kingtool/httptest?delay=18&connect_redirect=1

  • delay=18 是我自己配置的服務端動態參數,意為讓我的java后台sleep(18)秒,即18秒后返回響應報文
  • connect_redirect=1 是騰訊(微信)服務器配置的動態參數, 意為只觸發一次請求, 超時也不重發。
  • 為了解決ajax跨域問題, 請求鏈路為 前台頁面-->觸發ajax請求-->阿里雲ecs-->阿里雲ecs java代碼調用目標服務器真實地址

此時post請求一次我的阿里雲延遲返回接口, 18秒結束后, 后台日志只打印一次,成功解決.

我的請求報文"天行健,君子以自強不息,地勢坤,君子以厚德載物"在后台日志中的的確確只打印一了一次.

 

終極方案, 使用redis或memcache緩存【推薦】at 2018/05/04

不知為何之前方案的connect_redirect=1參數突然MMP失靈了,只能另尋出路。

由於面向互聯網的接口,多次相同報文的請求的事實終究無法避免,要從根本上解決該問題, 還是得從服務方的角度出發:

  • 要么精簡自身系統以縮短處理時間繞開微信2次觸發問題,
  • 要么采用鎖機制控制第2次請求

於是又畫了以下時序圖,核心思想在於讓第2次的處理從第1次的請求結果中去拿。

而在集群模式下,A系統集群中的各server無法感知其它server的處理情況,所以解決重點在於使用獨立的redis或memcache緩存,並配以自動失效時間以保證內存的穩定性(防緩存無限增大),采用該方案后可看到第2次綠條的處理時間明顯比第1次紅條短多了。

 (在下圖樣例中 假設A系統處理業務需要11秒,  那么第2次不會再處理業務,最多比第一次多等1~2秒左右 , 最終就算2次觸發響應時間最多也不會超過12秒,)

 

簡要流程說明

  1. 以第一次紅條運行時間11秒為前提
  2. 首先計算請求報文的md5值, 作為緩存的key,也就是查詢要用的唯一識別碼,
  3. 0.5秒時,第一次的紅條請求到達, 以md5為key去緩存中查詢對應的value,必然為空,1秒時,設置對應value為0,作為正在處理的標志.
  4. 然后第一次紅條請求一直在處理中,時間往下嘀嗒嘀嗒走到10秒,
  5. 此時時間超過了10秒,
  6. 10.1秒時,第二次的綠條請求到達,還是以md5為key去緩存中查詢對應的value,10.8秒去查詢的時候會查到md5對應的value為0,發現該條數據正在被第一次的紅條處理中,好吧,那綠條每隔1秒再去查詢md5對應的value, 判斷是否已處理完(非0)了
  7. 11秒時,第一次的紅條請求順利結束,把緩存中md5對應value從0更新成返回的業務報文(非0),作為處理完成的標志.
  8. 11.8秒(相當於12秒),第二次的綠條發現,緩存中md5為key對應的value,已從0更新成了返回業務報文(非0),那么就把該返回業務報文作為真正需要的業務報文返回出去,經歷時間大約12秒左右.
  9. 於是,當第一次請求如果需要17秒處理時間,那么每二次會在17+1秒返回, 當第一次如果需要23秒處理時間,第二次請求會在23+1秒返回,依次類推.

 補充說明

  • 至於是否用0作為正在處理標志位,依據你的業務而定, 要是業務本身就返回0或1,那肯定需要換成true,false或其它特殊字符作為正在處理標志了.
  • 另外如果您的業務本身請求就很頻率(比如平均每隔個5秒就會有請求過來, 而每次請求時間又需要個20來秒)那么本方法由於第二次請求需要線程阻塞在那,等着第一次處理結束,所以會不太適合, 可能會浪費大量線程資源 , 此時最好從業務本身角度出發看看能不能縮短處理時間, 要想魚和熊掌都能兼得,那各位哥請把自家的服務器和網絡硬件設備鍍層金吧.

 

 

 

 

 

 

 

 

他人現象

求助微信一次ajax請求,會訪問兩次 [問題點數:20分,無滿意結帖,結帖人showbo]--https://bbs.csdn.net/topics/391816470       24樓說:

我也遇到這樣的問題,微商城提交訂單,超過10秒鍾,微信瀏覽器重發,導致訂單重復提交的問題。攔截器里看到確實有兩次提交,確定我們代碼里不做超時重試,然后這種情況似乎跟手機有關,我的手機就沒有出現這樣的問題,其他兩個同事的手機就出現,巨坑

 

后台收到微信重復請求問題--https://blog.csdn.net/gotohomebye/article/details/78508741  作者說:

都困擾快2周了,網上各種查理不出頭緒,假如真是查出來問題這么嚴重的話,微信瀏覽器研發團隊不可能不重視,現在運行中的這么多微信公眾號不可能沒遇到類似問題。其他瀏覽器都是正常的,肯定代碼沒問題,微信瀏覽器的問題也不大

 

作者:whatlonelytear
本文地址:https://www.cnblogs.com/whatlonelytear/p/8934738.html
歡迎轉載,請在明顯位置給出出處及鏈接。

(1)  熱部署:就是容器狀態在運行的情況下重新部署整個項目.在這種情況下一般整個內存會清空,重新加載.簡單來說就是Tomcat或者其他的web服務器會幫我們重新加載項目.這種方式可能會造成sessin丟失等情況.  (2)熱加載:就是容器狀態在運行的情況下重新加載改變編譯后的類.在這種情況下內存不會清空,sessin不會丟失,但容易造成內存溢出,或者找不到方法。因為內存無法轉變成對像.一般改變類的結構和模型就會有異常,在已經有的變量和方法中改變是不會出問題的


免責聲明!

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



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