扫码登录实现

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

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

  • 获取二维码的 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 的调用

相关推荐
崔庆才丨静觅1 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60612 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了2 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅2 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅3 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅3 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment3 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅3 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊3 小时前
jwt介绍
前端
爱敲代码的小鱼3 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax