国产+高潮+在线,国产 av 仑乱内谢,www国产亚洲精品久久,51国产偷自视频区视频,成人午夜精品网站在线观看

workerman實現(xiàn)微信公眾號帶參數(shù)二維碼掃碼識別用戶

efnic

完整功能體驗

查看源代碼,有完整的通訊流程實現(xiàn)。
https://iyuu.cn
發(fā)表在自己的博客
https://www.iyuu.cn/archives/202/
?#說明
此功能是利用微信公眾號帶參數(shù)二維碼,實現(xiàn)掃碼識別用戶,并且實時通知前端掃碼狀態(tài),并非ajax輪詢!從而進(jìn)行后續(xù)的其他業(yè)務(wù)邏輯。

工作流程詳解

?1. 用workerman框架,編寫websocket服務(wù)后端監(jiān)聽2129端口,進(jìn)程啟動同時再監(jiān)聽一個內(nèi)部通訊5678端口,2129端口等待前端頁面發(fā)起連接:https://www.iyuu.cn/usr/index.html;
?2. 用戶進(jìn)入前端頁面,自動連接wss://www.iyuu.cn:2129;
?3. 用戶點擊獲取二維碼,請求二維碼生成接口:https://www.iyuu.cn/qrcode,返回二維碼參數(shù):
? json {"ticket":"gQH47zwAAAAAAAAAAS5odHRwOi8vd2VpeGluLnFxLmNvbS9xLzAycTMtdzlMVEhlYzIxcF9jQU50MWsAAgQHjGRdAwR4AAAA","expire_seconds":120,"uid":1735536450} ?
? 注:uid通過函數(shù)rand(1,4294967200)生成并查詢緩存,確保唯一后放入Redis緩存。
?4. 把二維碼參數(shù),轉(zhuǎn)發(fā)到websocket服務(wù)wss://www.iyuu.cn:2129,websocket服務(wù)保存轉(zhuǎn)發(fā)來的信息建立映射關(guān)系;
?5. 顯示二維碼:https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket={data.ticket},用戶掃碼
?6. 微信開發(fā)者接口會收到掃碼結(jié)果,獲取到場景值ID;
?7. 根據(jù)場景值ID從Redis緩存取出ticket校驗通過,執(zhí)行業(yè)務(wù)邏輯(登錄、綁定、解綁、積分等等),并通過5678端口實時通知用戶掃碼后的處理結(jié)果。

完整Websocket服務(wù)代碼

<?php
use Workerman\Worker;
use Workerman\Lib\Timer;
define("APP_PATH",  dirname(__FILE__));
// 心跳間隔40秒
define('HEARTBEAT_TIME', 40);
require_once __DIR__ . '/../../vendor/autoload.php';
require_once APP_PATH . '/Library/Function.php';
$context = array(
    'ssl' => array(
        // 請使用絕對路徑
        'local_cert'    => __DIR__ . '/../../Cert/www.iyuu.cn.crt',
        'local_pk'      => __DIR__ . '/../../Cert/www.iyuu.cn.key',
        'verify_peer'                => false,
        //'allow_self_signed' => true, //如果是自簽名證書需要開啟此選項
    )
);
$worker = new Worker('websocket://0.0.0.0:2129', $context);
$worker->transport = 'ssl';
$worker->name = 'WebSocket';
/*
 * 注意這里進(jìn)程數(shù)必須設(shè)置為1,否則會報端口占用錯誤
 * (php 7可以設(shè)置進(jìn)程數(shù)大于1,前提是$inner_text_worker->reusePort=true)
 */
$worker->count = 1;
// 新增加一個屬性,用來保存uid到connection的映射(uid是用戶id或者客戶端唯一標(biāo)識)
$worker->uidConnections = array();
// 當(dāng)有客戶端連接時
$worker->onConnect = function($connection)
{
    /*
    //定時10秒關(guān)閉這個鏈接,需要10秒內(nèi)發(fā)認(rèn)證并刪除定時器阻止關(guān)閉連接的執(zhí)行
    $connection->auth_timer_id = Timer::add(10, function(){
        $connection->close();
    });

    Timer::del($connection->auth_timer_id);
    */
};

// worker進(jìn)程啟動后創(chuàng)建一個text Worker以便打開一個內(nèi)部通訊端口
$worker->onWorkerStart = function($worker)
{
    sc('WebSocket服務(wù)進(jìn)程啟動成功!');
    // 開啟一個內(nèi)部端口,方便內(nèi)部系統(tǒng)推送數(shù)據(jù),Text協(xié)議格式 文本+換行符
    $inner_text_worker = new Worker('text://0.0.0.0:5678');
    $inner_text_worker->onMessage = function($connection, $buffer)
    {
        global $worker;
        if (empty($buffer)) return;
        // $data數(shù)組格式,里面有uid,表示向那個uid的頁面推送數(shù)據(jù)
        $data = json_decode($buffer, true);
        if (isset($data['uid'])) {
            $uid = $data['uid'];
            //uid + ticket雙重安全驗證(防止前端冒用隨機(jī)uid)
            $data['ticket'] = isset($data['ticket'])&&$data['ticket'] ? $data['ticket'] : '';
            $conn = $worker->uidConnections[$uid];
            $ticket = isset($conn->ticket)&&$conn->ticket ? $conn->ticket : '';
            if($data['ticket'] != $ticket){
                return;
            }
            // 通過workerman,向uid的頁面推送數(shù)據(jù)
            $ret = sendMessageByUid($uid, $buffer);
            // 返回推送結(jié)果
            $connection->send($ret ? 'ok' : 'fail');
        }
        return;
    };
    // ## 執(zhí)行監(jiān)聽 ##
    $inner_text_worker->listen();
    // 進(jìn)程啟動后設(shè)置一個每秒運行一次的定時器
    Timer::add(1, function()use($worker){
        $time_now = time();
        foreach($worker->uidConnections as $connection) {
            // 有可能該connection還沒收到過消息,則lastMessageTime設(shè)置為當(dāng)前時間
            if (empty($connection->lastMessageTime)) {
                $connection->lastMessageTime = $time_now;
                continue;
            }
            // 上次通訊時間間隔大于心跳間隔,則認(rèn)為客戶端已經(jīng)下線,關(guān)閉連接
            if ($time_now - $connection->lastMessageTime > HEARTBEAT_TIME) {
                if(isset($connection->uid))
                {
                    // 連接斷開時刪除映射
                    unset($worker->uidConnections[$connection->uid]);
                }
                $connection->close();
            }
        }
    });
    //每天重啟進(jìn)程
    Timer::add(86400, function()use($worker)
    {
        sc('WebSocket服務(wù)進(jìn)程定時重啟任務(wù),執(zhí)行成功!');
        Worker::stopAll();
    });
};

// 當(dāng)有客戶端發(fā)來消息時執(zhí)行的回調(diào)函數(shù)
$worker->onMessage = function($connection, $data)
{
    global $worker;
    // 給connection臨時設(shè)置一個lastMessageTime屬性,用來記錄上次收到消息的時間
    $connection->lastMessageTime = time();
    // 客戶端傳遞的是json數(shù)據(jù)
    if (empty($data)) return;
    $message = json_decode($data, true);
    if(empty($message)) return;
    if(isset($message['cmd'])) {
        // 根據(jù)類型執(zhí)行不同的業(yè)務(wù)
        switch($message['cmd'])
        {
            case 'ping':
                return;
            case 'login':
                return;
            case 'sms':
                return;
            case 'mail':
                return;
            default:
                return;
        }
    }else{
        // 判斷當(dāng)前客戶端是否已經(jīng)驗證,即是否設(shè)置了uid
        if(isset($connection->uid))
        {
            //上次uid和ticket過期
            if (isset($message['uid']) && ($message['uid']!=$connection->uid)) {
                unset($worker->uidConnections[$connection->uid]);
            }
        }
        if (isset($message['uid']) && $message['uid']) {
            // 沒驗證的話把第一個包當(dāng)做uid
            $connection->uid = $message['uid'];
            if (isset($message['ticket'])) {
                //帶參數(shù)二維碼的ticket
                $connection->ticket = $message['ticket'];
            }
            /* 保存uid到connection的映射,這樣可以方便的通過uid查找connection,
            * 實現(xiàn)針對特定uid推送數(shù)據(jù)
            */
            $worker->uidConnections[$connection->uid] = $connection;
            $connection->send($data);
            return;
        } else {
            //不帶uid的消息
            # code...
        }
    }
};

// 當(dāng)有客戶端連接斷開時
$worker->onClose = function($connection)
{
    global $worker;
    if(isset($connection->uid))
    {
        // 連接斷開時刪除映射
        unset($worker->uidConnections[$connection->uid]);
    }
};
// 進(jìn)程關(guān)閉時
$worker->onWorkerStop = function($worker)
{
    //通知運維人員
    //sc('WebSocket服務(wù)進(jìn)程退出,如非定時重啟,請檢查!');
};
// 針對uid推送數(shù)據(jù)
function sendMessageByUid($uid, $message)
{
    global $worker;
    if(isset($worker->uidConnections[$uid]))
    {
        $connection = $worker->uidConnections[$uid];
        $connection->send($message);
        return true;
    }
    return false;
}

// 如果不是在根目錄啟動,則運行runAll方法
if(!defined('GLOBAL_START'))
{
    Worker::runAll();
}

前端頁面關(guān)鍵代碼

<!DOCTYPE html> 
<html> 
<head> 
<meta charset="UTF-8" />
<title>微信公眾號模板消息通知Token申請頁 - 大衛(wèi)科技blog www.iyuu.cn</title>
<meta name="keywords" content="大衛(wèi)科技blog,www.iyuu.cn" />
<meta name="description" content="微信公眾號模板消息通知Token申請頁" />
<meta name="copyright" content="海南大衛(wèi)電子科技有限公司" />
<meta name="author" content="大衛(wèi)" />
<script src="https://cdn.bootcss.com/jquery/1.12.4/jquery.min.js"></script>
</head>
<body>
<div id="panel">
    <div id="header">
        <h1>微信公眾號模板消息通知<span>Token申請頁</span></h1>
        <noscript><h1>你的瀏覽器不支持 JavaScript,請啟用 JavaScript 后訪問。</h1></noscript>
        <address>制作 by <a >大衛(wèi)科技blog</a></address>
    </div>
    <div id="token" style="display: none;"></div>
    <div id="qrcode">點擊下面的按鈕,獲取微信二維碼!</div>
    <div id="expire" style="display: none;">請盡快使用手機(jī)微信掃碼,二維碼<span id="dd">120</span>秒后過期。</div>  
    <a class="J_scanWeixin">獲取微信二維碼</a>
</div>
<script type="text/javascript">
var ws,ping_t,qrcode_t,expire_t;
var WEB_URL  = {
    QRCODE_IMG_URL : 'https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=',
    wshost : 'wss://www.iyuu.cn:2129',      //websocket服務(wù)器地址
};
// 連接服務(wù)器
function connect() {
    ws = new WebSocket(WEB_URL.wshost);
    ws.onopen = function(e) {
        console.log(ws);
        console.log("Server onOpen",e);
        ping_t = setInterval(function(){
            ws.send('{"cmd":"ping"}');
            console.log("ping Server");
        }, 30000);
    };
    ws.onmessage = onmessage;
    ws.onclose = function(e) {
        console.log("Server onClose",e.data);
        //關(guān)閉定時器
        if (typeof ping_t !="undefined")
        {
            clearInterval(ping_t);
            console.log("clearInterval ping_t");
        }
        if (typeof qrcode_t !="undefined")
        {
            clearInterval(qrcode_t);
            console.log("clearInterval qrcode_t");
        }
    };
    ws.onerror = function(e) {
        connect();
        console.log("Server onError",e.data);
    };
}

function onmessage(e)
{
    var timestamp = new Date().getTime();
    var data = JSON.parse(e.data);  //JSON.parse() 將 JSON字符串轉(zhuǎn)換為對象。
    if (typeof data.cmd != 'undefined')
    {
        switch(data.cmd){
            case 'login':
                window.location='/admin/login.php?token='+data.token;
            break;
            case 'scan':
                console.log('Server Cmd scan',e.data);
            break;
            case 'bind':
                console.log('Server Cmd bind',e.data);
            break;
            default:   //服務(wù)器下發(fā)其他指令
                console.log('Server Cmd?',e.data);
            break;
        }
    }else{
        if (typeof data.token != 'undefined')
        {
            clearInterval(expire_t);
            clearInterval(qrcode_t);
            $("#token").html("<h3>您的Token是:"+ data.token +"</h3><br /><h3>請求URL是:https://www.iyuu.cn/"+ data.token +".send</h3>");
            $("#token").show();
            $("#qrcode").hide();
            $("#expire").hide();
            $(".J_scanWeixin").hide();
        }       
    }   
    console.log('收到Server消息',e.data);
}
connect();
//dom載入完畢執(zhí)行
$(function(){
    //點擊按鈕,顯示二維碼
    $('.J_scanWeixin').click(function(){
        if (ws.readyState == 1)
        {
            $.get("/qrcode",function(ret){
                ws.send(ret);   //發(fā)送uid
                var data = JSON.parse(ret);
                $("#qrcode").html("<img class='' src='"+ WEB_URL.QRCODE_IMG_URL + escape(data.ticket) +"' width='375' height='375' />");
                $(".J_scanWeixin").hide();  //隱藏獲取二維碼按鈕
                $("#qrcode").show();
                $("#expire").show();    //顯示倒計時
                //掃碼提示
                qrcode_t = setTimeout(function(){
                    $("#qrcode").hide();                    
                    $("#expire").hide();
                    $(".J_scanWeixin").show();
                }, data.expire_seconds*1000);

                var dd = data.expire_seconds;               
                expire_t = setInterval(function(){
                    if(dd <=1){
                        clearInterval(expire_t);
                    }
                    dd--;                   
                    $("#dd").html("<b>"+ dd +"</b>");
                }, 1000);
            });
        }else{
            $("#qrcode").html("<b>Websocker鏈接失敗,請刷新頁面重試!</b>");
            $(".J_scanWeixin").hide();  //隱藏獲取二維碼按鈕
        }       
    });
});
</script>
</body>
</html>

執(zhí)行方法:

?
? ? /磁盤/路徑/php /路徑/start_wss.php start -d

6534 3 2
3個評論

智佳思遠(yuǎn)

mark,以后應(yīng)該會有用

  • 暫無評論
wayhbbeed

直接使用gateway貌似更簡單些

  • 暫無評論
jonychen1

先給博主贊一個,寫得很詳細(xì),不過要是基礎(chǔ)差點的朋友可能實踐起來有點難,建議博主可以直接在第三方websocket推送框架上直接進(jìn)行開發(fā),那樣感覺會更方便些,推薦GoEasy,我一般都會用,因為它提供完整的websocket前后端解決方案,支持多種前后端語言的使用,所以哪怕只做前端或者只做后端的朋友也可以用,www.goeasy.io 有興趣可以試一下怎么樣

  • 暫無評論
年代過于久遠(yuǎn),無法發(fā)表評論

efnic

3514
積分
0
獲贊數(shù)
0
粉絲數(shù)
2019-08-27 加入
??