扫码登录实现

平时我们在使用软件的时候常见的扫码登录是怎么实现的呢?今天学习了一下

具体的实现流程是需要后端提供三个接口

  • 获取二维码的 key
  • 依据获取到的二维码 key 获取到 qrurl 来生成图片
  • 最后使用轮询来判断二维码的状态,是否已经扫码,二维码是否过期,是否是在待确认亦或是等待扫码

首先我们进行前面两步,初始化一个二维码

ts 复制代码
const [qrKey, setQrKey] = useState("");
const [qrUrl, setQrUrl] = useState("");
const [isLoading, setIsLoading] = useState(true);
const [error, setError] = useState("");

const initQrCode = async () => {
  
      const {
        data: { unikey },
      } = await getQrCodeKey();
      const {
        data: { qrurl },
      } = await getQrCodeImg(unikey);
      setQrKey(unikey);
      setQrUrl(qrurl);
      setIsLoading(false);
 
  };

这里我是用的 react

useEffect 里面调用初始化一下

ts 复制代码
  useEffect(() => {
    initQrCode();
  }, []);

那我们拿到了 qrurl 之后,是一个字符串,那我们要如何给转换成二维码的形式呢?

一种方式是后端直接生成二维码图片,我们前端直接展示即可

一种是给我们 一个url 我们通过 canvas 或者是第三方库转换成二维码图片展示

一般情况下都是由前端来生成,减少对服务器的压力

这时就需要 qrcode.react这个库

bash 复制代码
pnpm i qrcode.react

里面有一些对应的属性,比如设置宽高,前景色,背景色,透明度,容错等级,标题等等,具体属性可以去文档查看

其中里面最重要的属性就是 value 填入我们第二步返回的 qrurl,这样二维码图片就展示出来了

下面的就是第三步,也是最重要的,就是使用轮询向检测状态的接口发送数据

这里会有几个状态,我们使用枚举定义一下

ts 复制代码
enum QRCodeStatus {
  EXPIRED = 800, // 等待超时,二维码失效
  WAITING = 801, // 等待扫码
  CONFIRMED = 802, // 已经扫码,等待确认登录
  SUCCESS = 803,  // 确认登录
}

轮询检查二维码状态

ts 复制代码
  useEffect(() => {
    if (!qrKey) return;

     // 使用间歇定时器,每 1.5s 发送一条请求查看二维码状态
    const timer = setInterval(async () => {
      
        const { code } = await checkQrCodeStatus(qrKey);
        
        switch (code) {
          case QRCodeStatus.SUCCESS:
            clearInterval(timer);
            window.location.reload(); // 状态码是成功,重新刷新页面或是跳转到首页
            break;
          case QRCodeStatus.EXPIRED:
            clearInterval(timer);
            setError("二维码已过期,点击刷新"); // 设置错误提示信息
            break;
        }
    
    }, 1500);

    return () => clearInterval(timer); // 这里在最后要清除副作用,避免内存泄露
  }, [qrKey]);

可以看到这里每 1.5s 就会发送一条请求验证二维码的状态

如果我们的状态为超时,那么就需要设置错误信息,在二维码的前置一个遮罩层提示二维码状态过期,需要重新加载

代码的具体实现

tsx 复制代码
import { QRCodeSVG } from "qrcode.react";

<div className="flex flex-col items-center gap-4">
      <div className="relative w-[200px] h-[200px] flex-center">
        <div className=" flex-center rounded-2xl bg-white">
          {isLoading ? (
            <div className="text-center">正在生成二维码...</div>
          ) : (
            <QRCodeSVG value={qrUrl} size={168} level="H" />
          )}
        </div>

        {error && (
          <div className="absolute inset-0 bg-[#fff] bg-opacity-20 backdrop-blur-sm flex flex-col items-center justify-center rounded-2xl backdrop-blur-sm">
            <p className="text-white text-center px-2">{error}</p>
            <Button
              onClick={handleReload}
              className="mt-2 !bg-blue-500 !text-white"
              size="small"
            >
              重新获取
            </Button>
          </div>
        )}
      </div>
    </div>

当然这只是扫码登录的流程的一个简单实现,具体的代码优化也可以添加 isMounted 标记,处理组件卸载后可能的 setState 的调用

相关推荐
wdfk_prog5 小时前
嵌入式面试真题第 10 题:高优化等级下共享状态可见性、内存模型与系统级同步设计
java·linux·开发语言·面试·职场和发展·架构·c
谭光志6 小时前
Vibe Coding 时代,程序员该何去何从
前端·后端·ai编程
胡萝卜术7 小时前
RAG 的知识炼油厂:从原始网页到可检索知识块的工程化之路
面试·架构·github
wdfk_prog7 小时前
嵌入式面试真题第 11 题:RTOS 优先级翻转与实时任务阻塞的通用治理
c语言·缓存·面试·职场和发展·架构
仿生狮子8 小时前
别再说“全栈”了,AI 时代团队只认这 5 种人
前端·人工智能·后端
kyriewen8 小时前
AI 写的 React 组件,合并前必查的 6 个坏味道——每个都有代码对比
前端·javascript·react.js
Highcharts.js8 小时前
软件开发公司为什么选择 Highcharts?
前端·前端框架·echarts·数据可视化·技术选型·highcharts·图表工具
多加点辣也没关系9 小时前
JavaScript|第13章:原始类型的方法
开发语言·javascript·ecmascript
এ慕ོ冬℘゜9 小时前
深入理解 JavaScript 事件体系:Window、鼠标与键盘事件详解
开发语言·javascript·okhttp
阿祖zu9 小时前
企业 AI 转型之痛,个人提效十倍不止,组织效率仍止步不前?
前端·aigc·agent