1. 程式人生 > >利用長輪詢實現微信網頁版掃碼登入

利用長輪詢實現微信網頁版掃碼登入

掃碼登入操作過程

  • 手機登入微信,利用“掃一掃”功能掃描網頁上的二維碼
  • 手機掃描成功後,提示“登入網頁版微信”;網頁上顯示“成功掃描 請在手機點選確認以登入”
  • 手機端點選“登入網頁版微信”,網頁跳轉到使用者的微信操作介面

整個掃碼登入的操作過程還是挺簡單的,而且互動地實時性比較好,如果網路不是非常阻塞,整個過程還是非常快的。

掃碼登入原理

掃碼登入大概的思路是:微信手機客戶端從網頁二維碼裡面得到一些資訊,然後傳送給網頁微信的伺服器,網頁伺服器驗證資訊並響應。下面,我們藉助火狐瀏覽器提供的Firebug工具看看,到底是怎麼一回事兒吧!

1.每次開啟微信網頁版的時候,都會生成一個含有唯一uid

的二維碼,而且每次重新整理後都會改變。這樣可以保證一個uid只可以繫結一個賬號和密碼,確定登入使用者的唯一性。可以通過手機上的UC瀏覽器提供的掃碼功能檢視二維碼裡面的資訊,但並不會自動開啟該地址。我重新整理三次,掃描結果如下,其中最後面那串數字就是uid

1) https://login.weixin.qq.com/l/48e24d66bdbc4f
2) https://login.weixin.qq.com/l/0787fb4fa7ad4c
3) https://login.weixin.qq.com/l/92781a4a7f1c47

通過檢視網頁原始碼,這個頁面在載入完畢時,已經把很多登入後才需要的相關資源都預先載入進來了,所以登入使用者得到確認後展示使用者資訊的速度很快。

2.除了返回唯一的uid,實際上開啟這個頁面的時候,瀏覽器跟伺服器還建立了一個長連線,請求uid的掃描記錄。如果沒有,在特定時長後(目前是27秒左右)會接到狀態碼408(請求超時),表示應該繼續下一次請求;如果接到狀態碼201(伺服器建立新資源成功),表示客戶端掃描了該二維碼。

請求超時:返回408

408

掃碼成功:返回201

201

長輪詢程式碼結構:

Js程式碼  收藏程式碼
  1. function _poll(_asUUID) {  
  2.   // ....  
  3.   $.ajax({  
  4.     type: "GET",  
  5.     url: "https://login." + _sBaseHost + "/cgi-bin/mmwebwx-bin/login?uuid="
     + _asUUID + "&tip=" + show_tip,  
  6.     dataType: "script",  
  7.     cache: false,  
  8.     timeout: _nAjaxTimeout,  
  9.     success: function(data, textStatus, jqXHR) {  
  10.       switch (_aoWin.code) {  
  11.       case 200:  
  12.         // ....  
  13.         break;  
  14.       case 201:  
  15.         // ....  
  16.         break;  
  17.       case 408:  
  18.         // ....  
  19.         break;  
  20.       case 400:  
  21.       case 500:  
  22.         // ....  
  23.         break;  
  24.       }  
  25.     },  
  26.     error: function(jqXHR, textStatus, errorThrown) {  
  27.         // ....  
  28.     }  
  29.   });  
  30. }  

/** 長輪詢知識介紹開始 */

基於HTTP的長連線,是一種通過長輪詢方式實現"伺服器推"的技術,它彌補了HTTP簡單的請求應答模式的不足,極大地增強了程式的實時性和互動性。

一、什麼是長連線、長輪詢?

用通俗易懂的話來說,就是客戶端不停的向伺服器傳送請求以獲取最新的資料資訊。這裡的“不停”其實是有停止的,只是我們人眼無法分辨是否停止,它只是一種快速的停下然後又立即開始連線而已。

二、長連線、長輪詢的應用場景

長連線、長輪詢一般應用與WebIM、ChatRoom和一些需要及時互動的網站應用中。其真實案例有:WebQQ、Hi網頁版、Facebook IM等。

三、優缺點

輪詢:客戶端定時向伺服器傳送Ajax請求,伺服器接到請求後馬上返回響應資訊並關閉連線。 
優點:後端程式編寫比較容易。 
缺點:請求中有大半是無用,浪費頻寬和伺服器資源。 
例項:適於小型應用。


長輪詢:客戶端向伺服器傳送Ajax請求,伺服器接到請求後hold住連線,直到有新訊息才返回響應資訊並關閉連線,客戶端處理完響應資訊後再向伺服器傳送新的請求。 
優點:在無訊息的情況下不會頻繁的請求,耗費資源小。 
缺點:伺服器hold連線會消耗資源,返回資料順序無保證,難於管理維護。 
例項:WebQQ、Hi網頁版、Facebook IM。

長連線:在頁面裡嵌入一個隱蔵iframe,將這個隱蔵iframe的src屬性設為對一個長連線的請求或是採用xhr請求,伺服器端就能源源不斷地往客戶端輸入資料。 
優點:訊息即時到達,不發無用請求;管理起來也相對方便。 
缺點:伺服器維護一個長連線會增加開銷。 
例項:Gmail聊天


Flash Socket:在頁面中內嵌入一個使用了Socket類的 Flash 程式JavaScript通過呼叫此Flash程式提供的Socket介面與伺服器端的Socket介面進行通訊,JavaScript在收到伺服器端傳送的資訊後控制頁面的顯示。 
優點:實現真正的即時通訊,而不是偽即時。 
缺點:客戶端必須安裝Flash外掛;非HTTP協議,無法自動穿越防火牆。 
例項:網路互動遊戲。

四、實現原理

所謂長連線,就是要在客戶端與伺服器之間建立和保持穩定可靠的連線。其實它是一種很早就存在的技術,但是由於瀏覽器技術的發展比較緩慢,沒有為這種機制的實現提供很好的支援。所以要達到這種效果,需要客戶端和伺服器的程式共同配合來完成。通常的做法是,在伺服器的程式中加入一個死迴圈,在迴圈中監測資料的變動。當發現新資料時,立即將其輸出給瀏覽器並斷開連線,瀏覽器在收到資料後,再次發起請求以進入下一個週期,這就是常說的長輪詢(long-polling)方式。如下圖所示,它通常包含以下幾個關鍵過程:

image

1. 輪詢的建立 
建立輪詢的過程很簡單,瀏覽器發起請求後進入迴圈等待狀態,此時由於伺服器還未做出應答,所以HTTP也一直處於連線狀態中。 
2. 資料的推送 
在迴圈過程中,伺服器程式對資料變動進行監控,如發現更新,將該資訊輸出給瀏覽器,隨即斷開連線,完成應答過程,實現“伺服器推”。 
3. 輪詢的終止 
輪詢可能在以下3種情況時終止: 
  3.1. 有新資料推送 
   當迴圈過程中伺服器向瀏覽器推送資訊後,應該主動結束程式執行從而讓連線斷開,這樣瀏覽器才能及時收到資料。 
  3.2. 沒有新資料推送 
   迴圈不能一直持續下去,應該設定一個最長時限,避免WEB伺服器超時(Timeout),若一直沒有新資訊,伺服器應主動向瀏覽器傳送本次輪詢無新資訊的正常響應,並斷開連線,這也被稱為“心跳”資訊。 
  3.3. 網路故障或異常 
   由於網路故障等因素造成的請求超時或出錯也可能導致輪詢的意外中斷,此時瀏覽器將收到錯誤資訊。 
4. 輪詢的重建 
瀏覽器收到回覆並進行相應處理後,應馬上重新發起請求,開始一個新的輪詢週期。

五、程式設計

1、普通輪詢 Ajax方式

客戶端程式碼片段

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8" isELIgnored="false" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
    <head>
        <meta http-equiv="pragma" content="no-cache">
        <meta http-equiv="cache-control" content="no-cache">
        <meta http-equiv="author" content="hoojo & http://hoojo.cnblogs.com">
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <%@ include file="/tags/jquery-lib.jsp"%>
        <script type="text/javascript">
            $(function () {
                window.setInterval(function () {
                    $.get("${pageContext.request.contextPath}/communication/user/ajax.mvc", 
                        {"timed": new Date().getTime()}, 
                        function (data) {
                            $("#logs").append("[data: " + data + " ]<br/>");
                    });
                }, 3000);
            });
        </script>
    </head>
    <body>
        <div id="logs"></div>
    </body>
</html>

客戶端實現的就是用一種普通輪詢的結果,比較簡單。利用setInterval不間斷的重新整理來獲取伺服器的資源,這種方式的優點就是簡單、及時。缺點是連結多數是無效重複的;響應的結果沒有順序(因為是非同步請求,當傳送的請求沒有返回結果的時候,後面的請求又被髮送。而此時如果後面的請求比前面的請求要先返回結果,那麼當前面的請求返回結果資料時已經是過時無效的資料了);請求多,難於維護、浪費伺服器和網路資源。

伺服器端程式碼

@RequestMapping("/ajax")
public void ajax(long timed, HttpServletResponse response) throws Exception {
     PrintWriter writer = response.getWriter();
     Random rand = new Random();
     // 死迴圈 查詢有無資料變化
     while (true) {
         Thread.sleep(300); // 休眠300毫秒,模擬處理業務等
         int i = rand.nextInt(100); // 產生一個0-100之間的隨機數
         if (i > 20 && i < 56) { // 如果隨機數在20-56之間就視為有效資料,模擬資料發生變化
             long responseTime = System.currentTimeMillis();
             // 返回資料資訊,請求時間、返回資料時間、耗時
             writer.print("result: " + i + ", response time: " + responseTime + ", request time: " + timed + ", use time: " + (responseTime - timed));
             break; // 跳出迴圈,返回資料
         } else { // 模擬沒有資料變化,將休眠 hold住連線
             Thread.sleep(1300);
         }
     }
}

伺服器端實現,這裡就模擬下程式監控資料的變化。上面程式碼屬於SpringMVC 中controller中的一個方法,相當於Servlet中的一個doPost/doGet方法。如果沒有程式環境適應servlet即可,將方法體中的程式碼copy到servlet的doGet/doPost中即可。

伺服器端在進行長連線的程式設計時,要注意以下幾點: 
1. 伺服器程式對輪詢的可控性
 
由於輪詢是用死迴圈的方式實現的,所以在演算法上要保證程式對何時退出迴圈有完全的控制能力,避免進入死迴圈而耗盡伺服器資源。 
2. 合理選擇“心跳”頻率 
從圖1可以看出,長連線必須由客戶端不停地進行請求來維持,所以在客戶端和伺服器間保持正常的“心跳”至為關鍵,引數POLLING_LIFE應小於WEB伺服器的超時時間,一般建議在10~20秒左右。 
3. 網路因素的影響 
在實際應用時,從伺服器做出應答,到下一次迴圈的建立,是有時間延遲的,延遲時間的長短受網路傳輸等多種因素影響,在這段時間內,長連線處於暫時斷開的空檔,如果恰好有資料在這段時間內發生變動,伺服器是無法立即進行推送的,所以,在演算法設計上要注意解決由於延遲可能造成的資料丟失問題。 
4. 伺服器的效能 
在長連線應用中,伺服器與每個客戶端例項都保持一個持久的連線,這將消耗大量伺服器資源,特別是在一些大型應用系統中更是如此,大量併發的長連線有可能導致新的請求被阻塞甚至系統崩潰,所以,在進行程式設計時應特別注意演算法的優化和改進,必要時還需要考慮伺服器的負載均衡和叢集技術。

image

上圖是返回的結果,可以看到先發出請求,不一定會最先返回結果。這樣就不能保證順序,造成髒資料或無用的連線請求。可見對伺服器或網路的資源浪費。

2、普通輪詢 iframe方式

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8" isELIgnored="false" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
    <head>
        <meta http-equiv="pragma" content="no-cache">
        <meta http-equiv="cache-control" content="no-cache">
        <meta http-equiv="expires" content="0">
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <%@ include file="/tags/jquery-lib.jsp"%>
        <script type="text/javascript">
            $(function () {
                window.setInterval(function () {
                    $("#logs").append("[data: " + $($("#frame").get(0).contentDocument).find("body").text() + " ]<br/>");
                    $("#frame").attr("src", "${pageContext.request.contextPath}/communication/user/ajax.mvc?timed=" + new Date().getTime());
                    // 延遲1秒再重新請求
                    window.setTimeout(function () {
                        window.frames["polling"].location.reload();
                    }, 1000);
                }, 5000);
            });
        </script>
    </head>
    <body>
        <iframe id="frame" name="polling" style="display: none;"></iframe>
        <div id="logs"></div>
    </body>
</html>

這裡的客戶端程式是利用隱藏的iframe向伺服器端不停的拉取資料,將iframe獲取後的資料填充到頁面中即可。同ajax實現的基本原理一樣,唯一不同的是當一個請求沒有響應返回資料的情況下,下一個請求也將開始,這時候前面的請求將被停止。如果要使程式和上面的ajax請求一樣也可以辦到,那就是給每個請求分配一個獨立的iframe即可。下面是返回的結果:

image

其中紅色是沒有成功返回請求就被停止(後面請求開始)掉的請求,黑色是成功返回資料的請求。

3、長連線iframe方式

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8" isELIgnored="false" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
    <head>
        <meta http-equiv="pragma" content="no-cache">
        <meta http-equiv="cache-control" content="no-cache">
        <meta http-equiv="author" content="hoojo & http://hoojo.cnblogs.com">
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <%@ include file="/tags/jquery-lib.jsp"%>
        <script type="text/javascript">
            $(function () {
                window.setInterval(function () {
                    var url = "${pageContext.request.contextPath}/communication/user/ajax.mvc?timed=" + new Date().getTime();
                    var $iframe = $('<iframe id="frame" name="polling" style="display: none;" src="' + url + '"></iframe>');
                    $("body").append($iframe);
                    $iframe.load(function () {
                        $("#logs").append("[data: " + $($iframe.get(0).contentDocument).find("body").text() + " ]<br/>");
                        $iframe.remove();
                    });
                }, 5000);
            });
        </script>
    </head>
    <body>
        <div id="logs"></div>
    </body>
</html>

這個輪詢方式就是把剛才上面的稍微改下,每個請求都有自己獨立的一個iframe,當這個iframe得到響應的資料後就把資料push到當前頁面上。使用此方法已經類似於ajax的非同步互動了,這種方法也是不能保證順序的、比較耗費資源、而且總是有一個載入的條在位址列或狀態列附件(當然要解決可以利用htmlfile,Google的攻城師們已經做到了,網上也有封裝好的lib庫),但客戶端實現起來比較簡單。

 image

如果要保證有序,可以不使用setInterval,將建立iframe的方法放在load事件中即可,即使用遞迴方式。調整後的程式碼片段如下:

<script type="text/javascript">
    $(function () {
        (function iframePolling() {
            var url = "${pageContext.request.contextPath}/communication/user/ajax.mvc?timed=" + new Date().getTime();
            var $iframe = $('<iframe id="frame" name="polling" style="display: none;" src="' + url + '"></iframe>');
            $("body").append($iframe);
            $iframe.load(function () {
                $("#logs").append("[data: " + $($iframe.get(0).contentDocument).find("body").text() + " ]<br/>");
                $iframe.remove();
                // 遞迴
                iframePolling();
            });
        })();    
    });
</script>

這種方式雖然保證了請求的順序,但是它不會處理請求延時的錯誤或是說很長時間沒有返回結果的請求,它會一直等到返回請求後才能建立下一個iframe請求,總會和伺服器保持一個連線。和以上輪詢比較,缺點就是訊息不及時,但保證了請求的順序。

4、ajax實現長連線

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8" isELIgnored="false" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
    <head>
        <meta http-equiv="pragma" content="no-cache">
        <meta http-equiv="cache-control" content="no-cache">
        <meta http-equiv="expires" content="0">
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <%@ include file="/tags/jquery-lib.jsp"%>
        <script type="text/javascript">
            $(function () {
                (function longPolling() {
                    $.ajax({
                        url: "${pageContext.request.contextPath}/communication/user/ajax.mvc",
                        data: {"timed": new Date().getTime()},
                        dataType: "text",
                        timeout: 5000,
                        error: function (XMLHttpRequest, textStatus, errorThrown) {
                            $("#state").append("[state: " + textStatus + ", error: " + errorThrown + " ]<br/>");
                            if (textStatus == 
            
           

相關推薦

利用實現網頁登入

掃碼登入操作過程 手機登入微信,利用“掃一掃”功能掃描網頁上的二維碼手機掃描成功後,提示“登入網頁版微信”;網頁上顯示“成功掃描 請在手機點選確認以登入”手機端點選“登入網頁版微信”,網頁跳轉到使用者的微信操作介面 整個掃碼登入的操作過程還是挺簡單的,而且互動地實時性比較

網頁登入原理

微信網頁版登入步驟 2.  手機掃描二維碼,網頁出現使用者頭像 3.  手機確認登入 4.  網頁加載出使用者微信介面 手機一掃描二維碼,並且同意登入後,網頁上就能及時知道當前二維碼被掃描,使用者同意後,立馬就能加載出聊天介面,實時性非常高, 問題 那麼網頁是如何

利用實現模仿網頁登入邏輯生成驗證隨機數

掃碼登入核心邏輯過程: 1.頁面首先向伺服器請求一個URL地址+唯一隨機數 2.伺服器在資料庫記錄這條隨機數 3.頁面通過URL+隨機數資料生成二維碼,並持續詢問伺服器該隨機數狀態(PS:這是最關鍵的步驟) 4.手機通過掃描二維碼訪問伺服器,伺服器獲得隨

實現小程式,在PC端登陸並且自動跳轉頁面

通過微信小程式掃碼,在PC端登陸跳轉相應頁面 最近在做一個零食店,移動端採用微信小程式進行實現。當然,既然是零食店,那麼肯定會有後臺管理的,當時的想法是如何才能通過微信小程式裡進行掃碼去登陸PC端的管理平臺呢?話不多說,接下來就說說我是怎麼做到! 首先,大致上講一下我的實現思路,整體

Ecshop第三方授權登入介面檔案原始碼

《實現微信第三方授權掃碼登入》一文中tiandi簡單的敘述了一下如何實現微信第三方授權登入Ecshop系統以及公佈了核心程式碼,主要是修改了使用者的登入判定,即user.php這個檔案。 本文作為上一文的補充,上文提到過,另外還需要修改模板檔案和介面檔案。這裡的模板檔案主要是增加了微信使用者對老使

開放平臺登入

首先,頁面內容 引數官方API說的很清楚了,我就不重複闡述。 引數填正確後開啟這個頁面會顯示一個二維碼 接下來用微信掃碼,確定授權後這個頁面會自動跳轉到redirect_uri?code=xxx&state=xxxx 然後你就獲得了關鍵的東西之一code! 接下

使用&實現網頁聊天室

前言    如果有一個需求,讓你構建一個網路的聊天室,你會怎麼解決?    首先,對於HTTP請求來說,Server端總是處於被動的一方,即只能由Browser傳送請求,Server才能夠被動迴應。    也就是說,如果Browser沒有傳送請求,則Server就不能迴應。    並且HTTP具有無狀態的特點

手把手實現網頁授權和支付,附源代(VUE and thinkPHP)

nec ble 名單 ret 一次 hash 掃一掃 網頁 ada wechat github 手把手實現微信網頁授權和微信支付,附源代碼(VUE and thinkPHP) 概述 公眾號開發是痛苦的,痛苦在好多問題開發者文檔是沒有提到的,是需要你猜的. 在開發過程中翻

VueJs單頁應用實現網頁授權及分享功能示例

在實際開發中,無論是做PC端、WebApp端還是微信公眾號等型別的專案的時候,或多或少都會涉及到微信相關的開發,最近公司專案要求實現微信網頁授權,並獲取微信使用者基本資訊的功能及微信分享的功能,現在總算完成了,但開發過程中遇到好幾個坑。廢話不多說了,開始正題。 描述點 微信相關開發知識

JAVA實現網頁授權的實列程式碼

1、需要有一個公眾號(我這裡用的測試號),拿到AppID和AppSecret; 2、進入公眾號開發者中心頁配置授權回撥域名。具體位置:介面許可權-網頁服務-網頁賬號-網頁授權獲取使用者基本資訊-修改 注意,這裡僅需填寫全域名(如www.qq.com、www.baidu.c

TP5 實現網頁自定義分享

荊軻刺秦王 文章部分借鑑於:https://www.cnblogs.com/sunshineliulu/p/8034286.html 在實際操作中還有一些需要注意的問題: 1.登入微信公眾平臺,設定—公眾號設定—功能設定裡,填寫『JS介面安全域名』。填寫的域名須通過ICP備案的驗證,

JAVA開發 個人號 小機器人的實現 java封裝網頁

依賴於開源專案,GIT地址:https://github.com/biezhi/wechat-api 程式碼中有一些bug,需要自己改一改,然後就可以構建小機器人了 開發中遇到的棘手的問題,在拉取訊息的時候,視訊(VIDEO)格式的資料拉取不到,為空,經過嗅探,發現在訪問

網頁協議分析和實現機器人

開啟首頁,分配一個隨機uuid,根據該uuid獲取二維碼圖片。微信客戶端掃描該圖片,在客戶端確認登入。瀏覽器不停的呼叫一個介面,如果返回登入成功,則呼叫登入介面此時可以獲取聯絡人列表,可以傳送訊息。然後不斷呼叫同步介面。如果同步介面有返回,則可以獲取新訊息,然後繼續呼叫同步介面。Java版實現原始碼:htt

基於HTTP實現簡單推送

應用場景:裝置為安卓、PC以及伺服器,要求PC端能夠單向給移動端傳送訊息指令,安卓端解析訊息,進行後續處理動作。其中安卓端為基於Phonegap開發,說白了,就是HTML+JS。規模:正常應用為200移動端,PC端數量有限,不超過10臺,最多移動端為不超過500臺。 可以

PHP+TP框架實現網頁授權,獲取使用者資訊

一.準備工作. 1.將需要使用到的微信配置放在config.php配置檔案中方便獲取.(我使用的是微信測試號) return array( //'配置項'=>'配置值' 'appID'=>'wxf58**********f2e', '

一個簡單的php文件,實現網頁授權回調域名的代理轉發

host 代理 sco com 文件 lose mage 一個 time 一個簡單的php文件,實現微信網頁授權回調域名的代理轉發 <?php function is_HTTPS() { if (!isset($_SERVER[‘HTTPS‘

公眾號登陸原理及程式碼實現

1.使用者開啟公眾號點選掃碼功能(注意我們用 scancode_waitmsg這種型別即可)  2.使用者掃描了二維碼會給微信傳送資訊,然後微信把資訊以XML格式傳送給我們的伺服器 3.接收資料,並把資料保存於資料庫或者快取,程式碼如下: $wechatObj = new

兩行程式碼實現電腦多開

兩行程式碼實現的微信電腦版多開 首先在桌面建立一個 .bat檔案,我這裡命名 微信多開.bat 然後將 微信多開.bat 檔案用Notepad++或者記事本開啟將以下兩行程式碼複製貼上過去儲存即可實現多開的效果。 PATH C:\Program

網站使用網頁授權,qq登入

微信網頁授權 首先建立微信的第三方類庫 專案是tp5 所以我就放在了\extend\Oauth\wxlogin\WXlogin.php; <?php namespace Oauth\wxlogin; use think\Session; /** * 微信登入

網頁營銷軟體 防撤回 自動同意加好友

微信網頁版營銷軟體,可實現微信自動同意加好友、微信發訊息防撤回、微信群訊息防撤回、好友訊息自動回覆等功能。還可以實現各種群發好友資訊。此外好友發來的圖片等,可以實現自定義的儲存到本地資料夾。詳細的可以看下面的截圖:時崎慕意部落格原文地址:掃描全能王破解版 紙質文件掃描成文字電