<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??一站式輕松地調用各大LLM模型接口,支持GPT4、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                # 完整功能體驗 查看源代碼,有完整的通訊流程實現。 [https://iyuu.cn](https://www.iyuu.cn/usr/index.html) 發表在自己的博客 [https://www.iyuu.cn/archives/202/](https://www.iyuu.cn/archives/202/) ?#說明 此功能是利用微信公眾號帶參數二維碼,實現掃碼識別用戶,并且實時通知前端掃碼狀態,并非ajax輪詢!從而進行后續的其他業務邏輯。 # 工作流程詳解 ?1. 用workerman框架,編寫websocket服務后端監聽`2129端口`,進程啟動同時再監聽一個內部通訊`5678端口`,`2129端口`等待前端頁面發起連接:`https://www.iyuu.cn/usr/index.html`; ?2. 用戶進入前端頁面,自動連接`wss://www.iyuu.cn:2129`; ?3. 用戶點擊`獲取二維碼`,請求二維碼生成接口:`https://www.iyuu.cn/qrcode`,返回二維碼參數: ?`json {"ticket":"gQH47zwAAAAAAAAAAS5odHRwOi8vd2VpeGluLnFxLmNvbS9xLzAycTMtdzlMVEhlYzIxcF9jQU50MWsAAgQHjGRdAwR4AAAA","expire_seconds":120,"uid":1735536450} ?` ? 注:uid通過函數`rand(1,4294967200)`生成并查詢緩存,確保唯一后放入Redis緩存。 ?4. 把`二維碼參數`,轉發到websocket服務`wss://www.iyuu.cn:2129`,websocket服務保存轉發來的信息建立映射關系; ?5. 顯示二維碼:[https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket={data.ticket},用戶掃碼](https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket={data.ticket}%EF%BC%8C%E7%94%A8%E6%88%B7%E6%89%AB%E7%A0%81); ?6. 微信開發者接口會收到掃碼結果,獲取到場景值ID; ?7. 根據場景值ID從Redis緩存取出ticket校驗通過,執行業務邏輯(登錄、綁定、解綁、積分等等),并通過`5678端口`實時通知用戶掃碼后的處理結果。 # 完整Websocket服務代碼 ~~~php <?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'; /* * 注意這里進程數必須設置為1,否則會報端口占用錯誤 * (php 7可以設置進程數大于1,前提是$inner_text_worker->reusePort=true) */ $worker->count = 1; // 新增加一個屬性,用來保存uid到connection的映射(uid是用戶id或者客戶端唯一標識) $worker->uidConnections = array(); // 當有客戶端連接時 $worker->onConnect = function($connection) { /* //定時10秒關閉這個鏈接,需要10秒內發認證并刪除定時器阻止關閉連接的執行 $connection->auth_timer_id = Timer::add(10, function(){ $connection->close(); }); Timer::del($connection->auth_timer_id); */ }; // worker進程啟動后創建一個text Worker以便打開一個內部通訊端口 $worker->onWorkerStart = function($worker) { sc('WebSocket服務進程啟動成功!'); // 開啟一個內部端口,方便內部系統推送數據,Text協議格式 文本+換行符 $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數組格式,里面有uid,表示向那個uid的頁面推送數據 $data = json_decode($buffer, true); if (isset($data['uid'])) { $uid = $data['uid']; //uid + ticket雙重安全驗證(防止前端冒用隨機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的頁面推送數據 $ret = sendMessageByUid($uid, $buffer); // 返回推送結果 $connection->send($ret ? 'ok' : 'fail'); } return; }; // ## 執行監聽 ## $inner_text_worker->listen(); // 進程啟動后設置一個每秒運行一次的定時器 Timer::add(1, function()use($worker){ $time_now = time(); foreach($worker->uidConnections as $connection) { // 有可能該connection還沒收到過消息,則lastMessageTime設置為當前時間 if (empty($connection->lastMessageTime)) { $connection->lastMessageTime = $time_now; continue; } // 上次通訊時間間隔大于心跳間隔,則認為客戶端已經下線,關閉連接 if ($time_now - $connection->lastMessageTime > HEARTBEAT_TIME) { if(isset($connection->uid)) { // 連接斷開時刪除映射 unset($worker->uidConnections[$connection->uid]); } $connection->close(); } } }); //每天重啟進程 Timer::add(86400, function()use($worker) { sc('WebSocket服務進程定時重啟任務,執行成功!'); Worker::stopAll(); }); }; // 當有客戶端發來消息時執行的回調函數 $worker->onMessage = function($connection, $data) { global $worker; // 給connection臨時設置一個lastMessageTime屬性,用來記錄上次收到消息的時間 $connection->lastMessageTime = time(); // 客戶端傳遞的是json數據 if (empty($data)) return; $message = json_decode($data, true); if(empty($message)) return; if(isset($message['cmd'])) { // 根據類型執行不同的業務 switch($message['cmd']) { case 'ping': return; case 'login': return; case 'sms': return; case 'mail': return; default: return; } }else{ // 判斷當前客戶端是否已經驗證,即是否設置了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']) { // 沒驗證的話把第一個包當做uid $connection->uid = $message['uid']; if (isset($message['ticket'])) { //帶參數二維碼的ticket $connection->ticket = $message['ticket']; } /* 保存uid到connection的映射,這樣可以方便的通過uid查找connection, * 實現針對特定uid推送數據 */ $worker->uidConnections[$connection->uid] = $connection; $connection->send($data); return; } else { //不帶uid的消息 # code... } } }; // 當有客戶端連接斷開時 $worker->onClose = function($connection) { global $worker; if(isset($connection->uid)) { // 連接斷開時刪除映射 unset($worker->uidConnections[$connection->uid]); } }; // 進程關閉時 $worker->onWorkerStop = function($worker) { //通知運維人員 //sc('WebSocket服務進程退出,如非定時重啟,請檢查!'); }; // 針對uid推送數據 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(); } ~~~ ## 前端頁面關鍵代碼 ~~~html <!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>微信公眾號模板消息通知Token申請頁 - 大衛科技blog www.iyuu.cn</title> <meta name="keywords" content="大衛科技blog,www.iyuu.cn" /> <meta name="description" content="微信公眾號模板消息通知Token申請頁" /> <meta name="copyright" content="海南大衛電子科技有限公司" /> <meta name="author" content="大衛" /> <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 href="http://www.iyuu.cn/">大衛科技blog</a></address> </div> <div id="token" style="display: none;"></div> <div id="qrcode">點擊下面的按鈕,獲取微信二維碼!</div> <div id="expire" style="display: none;">請盡快使用手機微信掃碼,二維碼<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服務器地址 }; // 連接服務器 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); //關閉定時器 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字符串轉換為對象。 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: //服務器下發其他指令 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載入完畢執行 $(function(){ //點擊按鈕,顯示二維碼 $('.J_scanWeixin').click(function(){ if (ws.readyState == 1) { $.get("/qrcode",function(ret){ ws.send(ret); //發送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> ~~~ # 執行方法: ? ? ? /磁盤/路徑/php /路徑/start\_wss.php start -d
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看