场景题: “我们在 PC 网页上登录微信、或者淘宝时,经常会看到一个二维码。你用已登录的手机 App 扫一下,PC 网页就神奇地自动登录进去了。 你能从前端、后端、App 端三方的交互视角,把整个过程的底层原理详细描述一遍吗?”
扫码登录的核心逻辑,其实就是完成一次设备间的 Token(身份)转移。 PC 端由于没有账号密码,它通过请求一个印在二维码上的“凭据暗号(Token A)”。手机 端通过扫码捕获了这个暗号,然后告诉后端:“嘿,扫描这个暗号的人是我(Token B),你放 PC 端进去吧。”
我们仔细分为 4 个主要阶段进行拆解:
GET /api/qrcode/generate。qrCodeId(或者叫 UUID),并将其与状态(例如:status: WAIT_SCAN)存入 Redis 缓存,同时赋予它极短的过期时间(如 3 分钟)。qrCodeId 返回给 PC 浏览器。qrcode.js)把它包装成一张二维码图形渲染展示。GET /api/qrcode/check?id={qrCodeId},等待后端传来变化的消息。qrCodeId。POST /api/qrcode/scanned(携带自身的登录态 Token 以及 qrCodeId)。qrCodeId 的状态更改为 status: SCANNED,代表“已被某位大侠识别”。SCANNED,页面迅速响应出**"扫码成功,请在手机上确认"**的 UI 过渡画面并展示被模糊的用户头像)。POST /api/qrcode/confirm(同样携带自身 Token 及 qrCodeId)。qrCodeId 绑定在一起,并将 Redis 状态标记为 status: CONFIRMED,同时立刻在那头为 PC 端生成好专属的 PC 版 JWT Token。status。CONFIRMED!同时随信附上属于你的 Access-Token!”router.push 将页面飞驰跳转向系统首页。登录大捷。Q:为什么 PC 端要用轮询(Polling)去查?不能用 WebSocket 吗? A:完全可以用 WebSocket 甚至 Server-Sent Events (SSE)。事实上,如果系统的基建极为强大,使用 WebSocket 能免除轮询的海量无效 HTTP 开销,且服务端状态更新后前端能极其丝滑无延迟被驱动。 但在实际工程(比如微信老版本、京东扫码)中,轮询依旧占据极大数量。因为扫码页通常并不常驻,生命周期极短最多存在一分钟。与其为了一个扫码投入成本维护一条沉重的长连接、心跳机制还要防止断线重连,简单粗暴可依赖的“短轮询”,反而是工程 ROI(投资回报率)上极佳的选择。
Q:如果二维码过期了怎么办?
A:为了安全,生成 qrCodeId 时在 Redis 一定存在过期剔除机制。若 PC 轮询时接口返回 status: EXPIRED,前端需立刻挂起原二维码,浮上一层“二维码已过期,点击重置”的蒙层。阻止无效轮询请求继续攻击后端。用户点击后重复【阶段一】即可。