這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 需求描述 目前大多數PC端應用都有配套的移動端APP,如微信,淘寶等,通過使用手機APP上的掃一掃功能去掃頁面二維碼圖片進行登錄,使得用戶登錄操作更方便,安全,快捷。 思路解析 PC 掃碼原理? 掃碼登錄功能涉及到網頁端、伺服器和手機端, ...
這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助
需求描述
目前大多數PC端應用都有配套的移動端APP,如微信,淘寶等,通過使用手機APP上的掃一掃功能去掃頁面二維碼圖片進行登錄,使得用戶登錄操作更方便,安全,快捷。
思路解析
PC 掃碼原理?
掃碼登錄功能涉及到網頁端、伺服器和手機端,三端之間交互大致步驟如下:
- 網頁端展示二維碼,同時不斷的向服務端發送請求詢問該二維碼的狀態;
- 手機端掃描二維碼,讀取二維碼成功後,跳轉至確認登錄頁,若用戶確認登錄,則伺服器修改二維碼狀態,並返回用戶登錄信息;
- 網頁端收到伺服器端二維碼狀態改變,則跳轉登錄後頁面;
- 若超過一定時間用戶未操作,網頁端二維碼失效,需要重新刷新生成新的二維碼。
前端功能實現
如何生成二維碼圖片?
- 二維碼內容是一段字元串,可以使用uuid 作為二維碼的唯一標識;
- 使用qrcode插件 import QRCode from 'qrcode'; 把uuid變為二維碼展示給用戶
import {v4 as uuidv4} from "uuid" import QRCode from "qrcodejs2" let timeStamp = new Date().getTime() // 生成時間戳,用於後臺校驗有效期 let uuid = uuidv4() let content = `uid=${uid}&timeStamp=${timeStamp}` this.$nextTick(()=> { const qrcode = new QRCode(this.$refs.qrcode, { text: content, width: 180, height: 180, colorDark: "#333333", colorlight: "#ffffff", correctLevel: QRCode.correctLevel.H, render: "canvas" }) qrcode._el.title = ''
如何控制二維碼的時效性?
使用前端計時器setInterval, 初始化有效時間effectiveTime, 倒計時失效後重新刷新二維碼
export default { name: "qrCode", data() { return { codeStatus: 1, // 1- 未掃碼 2-掃碼通過 3-過期 effectiveTime: 30, // 有效時間 qrCodeTimer: null // 有效時長計時器 uid: '', time: '' }; }, methods: { // 輪詢獲取二維碼狀態 getQcodeStatus() { if(!this.qsCodeTimer) { this.qrCodeTimer = setInterval(()=> { // 二維碼過期 if(this.effectiveTime <=0) { this.codeStatus = 3 clearInterval(this.qrCodeTimer) this.qrCodeTimer = null return } this.effectiveTime-- }, 1000) } }, // 刷新二維碼 refreshCode() { this.codeStatus = 1 this.effectiveTime = 30 this.qrCodeTimer = null this.generateORCode() } },
前端如何獲取伺服器二維碼的狀態?
前端向服務端發送二維碼狀態查詢請求,通常使用輪詢的方式
- 定時輪詢:間隔1s 或特定時段發送請求,通過調用setInterval(), clearInterval()來停止;
- 長輪詢:前端判斷接收到的返回結果,若二維碼仍未被掃描,則會繼續發送查詢請求,直至狀態發生變化(失效或掃碼成功)
- Websocket:前端在生成二維碼後,會與後端建立連接,一旦後端發現二維碼狀態變化,可直接通過建立的連接主動推送信息給前端。
使用長輪詢實現:
// 獲取後臺狀態 async checkQRcodeStatus() { const res = await checkQRcode({ uid: this.uid, time: this.time }) if(res && res.code == 200) { let codeStatus - res.codeStatus this.codeStatus = codeStatus let loginData = res.loginData switch(codeStatus) { case 3: console.log("二維碼過期") clearInterval(this.qrCodeTimer) this.qrCodeTimer = null this.effectiveTime = 0 break; case 2: console.log("掃碼通過") clearInterval(this.qrCodeTimer) this.qrCodeTimer = null this.$emit("login", loginData) break; case 1: console.log("未掃碼") this.effectiveTime > 0 && this.checkQRcodeStatus() break; default: break; } } },