很多 App 里,扫码都是一个很常见的入口。
电视端登录,要用手机扫一下;网站付款,要扫一下;线下海报跳到 App,也需要扫一下;有些会员权益、设备绑定,也会把入口做成一个二维码。
从用户这边看,动作通常很简单:
打开扫码
↓
对准二维码
↓
识别成功
↓
页面跳转 / 登录成功 / 完成绑定 / 发起支付
写到代码里,可能只是:
scan()
或者:
handleScanResult(result)
扫码看起来像一个前端动作。打开相机,识别图案,拿到结果,再跳页面。
线上做久了,会发现扫码很少停在“识别出一段文字”。App 拿到那段内容以后,还要判断它属于哪个场景;后端要校验它还有效吗、被谁扫了、能不能被使用、使用后要改哪条业务状态。
一个扫码链路大概会经过:
App 打开扫码
↓
相机识别二维码
↓
拿到一段内容
↓
App 判断扫码类型
↓
请求对应业务后端
↓
后端校验有效期、身份、状态
↓
完成登录、支付、绑定或跳转
这一篇就从扫到一个二维码开始,看 App 到底拿到了什么,以及后面为什么还要交给业务系统处理。
一、二维码里通常只放一段内容

很多人第一次接触扫码,容易把二维码想得很神秘。
从 App 的角度看,二维码识别出来以后,拿到的通常就是一段字符串。
可能是一个网页地址:
https://example.com/activity/1001
可能是一个 App 内跳转地址:
myapp://video/detail?id=20001
可能是一个短码:
Q8K2M9
也可能是一串 token:
login_token=abc123xyz
二维码图案本身不负责登录,也不负责支付。它更多是在承载一段入口信息。
扫出来以后,App 要先看这段内容像什么。
比如:
像URL,就按网页或深链处理
像登录token,就走扫码登录
像订单码,就走扫码支付
像设备码,就走设备绑定
像活动短码,就走活动页或领券
同样是一段 URL,有的要打开 H5,有的要唤起 App 内页面,有的只是活动落地页,有的背后还要带登录态。App 如果只看到 https:// 就直接丢给浏览器,用户体验可能就断了。
所以扫码模块通常不会只负责“识别”。它还要负责把扫出来的内容分发给对应的业务。
二、扫码登录电视时,手机扫到的是临时凭证

扫码登录很适合接着上一篇投屏讲。
电视、投影、PC 这类设备上,经常不方便输入账号密码。屏幕上出现一个二维码,用户拿手机一扫,确认登录,登录就完成了。
从用户这边看,在电视上登录账号大概就几步:
电视展示二维码
↓
手机扫码
↓
手机弹出确认登录
↓
用户点确认
↓
电视登录成功
中间的链路,会比这个多几步。
第一步发生在电视端。
用户打开电视上的登录页时,电视不会直接等手机来找它。它会先向后端申请一次扫码登录请求:
电视:我要发起一次扫码登录
后端:给你一个 login_token
后端会生成一条临时记录:
login_token: abc123
device_id: tv_001
status: waiting
expires_at: 2 分钟后
这个 login_token 会被放进二维码里。电视把二维码展示出来以后,还会继续问后端:
abc123 有人确认了吗?
abc123 过期了吗?
abc123 登录成功了吗?
有的电视端会隔几秒查一次,有的会和后端保持一条连接,等状态变化。用户肉眼看到的就是登录页一直停在那里,二维码过一会儿会刷新。
第二步发生在手机端。
手机 App 扫到二维码后,拿到的就是 abc123 这段临时凭证。App 会把它发给后端:
手机:我扫到了 abc123
后端:这个码还有效,来自一台电视
这时手机端通常不会立刻让电视登录,会先弹出一个确认页:
是否允许这台设备登录?
设备:客厅电视
时间:刚刚
用户点确认后,手机再把自己的登录态一起带给后端:
手机:当前用户 user_10086 同意 abc123 登录
后端:把 abc123 的状态改成 confirmed
后端:记录 user_10086 要登录 tv_001
到这一步,后端拿到的结果大概是:
login_token: abc123 已确认
确认人: user_10086
登录设备: tv_001
确认时间: 10:30:21
也就是说,后端现在知道一件事:手机上这个已登录用户,同意让那台电视登录。
但同意以后,电视也不一定马上登录成功。
很多 App 会限制同一个账号能登录多少台设备。比如一个账号最多允许 3 台设备在线,用户手机、平板、另一台电视已经登录过了,这时再扫一台新电视,后端还要多查一步:
user_10086 当前已经登录了哪些设备?
这些设备有没有超过数量限制?
新设备 tv_001 能不能加入?
是否要挤掉旧设备?
是否要让用户手动选择退出哪台设备?
常见处理方式有几种。
一种是直接拒绝:
当前账号登录设备已达上限
请先退出其他设备后再登录
一种是让用户选择踢掉某台旧设备:
手机
平板
卧室电视
用户选中“卧室电视”后,后端把旧设备的登录态失效,再给新电视发放登录态。
还有一种是按规则自动挤掉最早登录或最久没用的设备。用户扫完以后,新电视登录成功,另一台设备再打开时会提示账号已在其他设备登录。
所以扫码确认只是说明“这个用户同意这台电视登录”。账号能不能再加一台设备,还要看后端的设备管理规则。
第三步又回到电视端。
电视一直在等 abc123 的状态。等后端把它改成 confirmed,电视端就能从后端拿到自己的登录结果:
电视:abc123 现在怎么样了?
后端:已经确认,这是你的登录凭证
电视:保存登录态,进入首页
所以这条链路里,手机和电视一般不会直接交换账号密码。手机是在后端确认“我这个已登录用户,同意让那台正在等待的设备登录”。
二维码承载的是一次临时登录请求的编号。电视创建它,手机确认它,后端负责把手机用户和电视设备对上。
所以扫码登录里会有几个细节:
二维码要过期
一个码只能用一次
确认前要展示设备信息
确认后电视端才能拿到登录态
取消或超时后,电视端要刷新二维码
如果二维码不过期,被人拍下来,过很久再扫,风险就很大。扫码登录不能只看扫出来的是哪段 token,还要看这段 token 现在是等待确认、已经确认、已经取消、已经过期,还是已经用过。
三、扫码支付扫出来的是什么

扫码支付要分场景看。
在 App 里买会员、买商品,大多数时候不会让用户再扫一个码。App 会直接拉起微信、支付宝或银行卡收银台。扫码支付常出现在两类场景里。
一类是网站或 PC 页面付款。
比如用户在网页上下单,页面上出现一个微信支付或支付宝二维码。用户拿手机扫码,手机里打开支付确认页,输入密码或刷脸后完成付款。
这时二维码里通常不会放“这笔钱已经付了”。它放的是一个支付入口,常见是支付平台生成的一段支付链接或预支付单标识:
pay_url: weixin://wxpay/bizpayurl?pr=xxxx
或者:
prepay_id: wx202406020001
out_trade_no: order_90001
amount: 199.00
expires_at: 2 分钟后
网页上的二维码一般是商户后端提前向支付平台申请来的。
链路会先从网站那边开始:
用户在网站下单
↓
网站后端创建业务订单
↓
网站后端向微信 / 支付宝创建支付单
↓
支付平台返回二维码内容
↓
网页把二维码展示出来
用户扫码时,手机上的微信或支付宝识别二维码,打开支付平台自己的确认页。用户看到收款方、金额、订单信息,再确认付款。
付款完成后,网页不会因为“用户扫过码”就把订单改成已支付。支付平台收款成功后,会通知网站后端:
用户扫码并确认付款
↓
支付平台扣款成功
↓
支付平台回调网站后端
↓
网站后端校验签名、金额、订单号
↓
网站后端更新支付单
↓
业务订单变成已支付
网页上的状态通常靠轮询更新:
网页每隔几秒问后端:
这笔订单支付成功了吗?
后端收到支付平台回调之前,网页最多只能显示“等待支付”或“支付处理中”。后端确认以后,页面才会跳到支付成功。
第二类是扫商家的收款码。
比如在小店、停车场、自助机前面,用户打开微信或支付宝扫一扫,对准商家贴出来的二维码。
这个二维码里通常放的是收款方信息,也可能带一个临时订单号:
merchant_id: M10001
store_id: S008
cashier_id: C03
order_token: P202406020001
有些固定收款码只知道收款方,不知道金额。用户扫完以后,要自己输入金额。
有些订单码已经带好了金额,比如停车缴费、自助售货机、餐厅桌台码。用户扫完以后,支付页面会展示对应订单:
收款方:某某停车场
金额:12.00
订单:停车费 O90001
这里也不能只相信二维码里的内容。
支付平台或商户后端会查一次:
商户是否存在
订单是否存在
金额是否一致
订单是否已经支付
二维码是否过期
当前码是否已经使用过
用户确认付款以后,后面的结果仍然要靠支付平台通知后端。商户页面、停车杆、自助机、商家后台看到的“已支付”,都是后端收到支付结果以后再更新出来的。
扫码支付可以分成两段看。
第一段是扫码拿到支付入口:
二维码
↓
支付链接 / 预支付单 / 商户码 / 订单码
↓
打开微信、支付宝或收银台
第二段是支付完成后的状态确认:
用户确认付款
↓
支付平台扣款
↓
支付平台通知业务后端
↓
业务后端更新订单
↓
网页、商户设备或 App 查询后端,展示支付结果
这里要分清扫码成功和支付成功。
扫码只是打开了支付入口。用户可能取消,可能输错密码,可能余额不足,也可能支付平台已经扣款但页面还没来得及刷新。可靠的结果还是要以后端收到支付平台通知为准。
四、扫码绑定设备时,二维码代表一台设备

设备绑定也经常用二维码。
比如智能电视、摄像头、投影仪、音箱、打印机,第一次接入 App 时,设备屏幕上或机身贴纸上会放一个二维码。
用户一扫,App 就知道要绑定哪台设备。
二维码里可能是:
device_id
device_sn
配网 token
绑定 token
设备型号
厂商信息
这时 App 拿到的是设备身份标识,还没有拿到这台设备的控制权。
后面还要经过后端确认:
设备是否存在
设备是否已经被别人绑定
当前用户是否有绑定权限
设备是否在线
是否需要输入验证码或按设备按钮确认
有些设备绑定还会要求用户在设备上按一下确认键,或者输入屏幕上显示的验证码。
这样做是为了确认扫的人确实接触到了这台设备,避免别人只拿到一张二维码图片就完成绑定。
设备绑定成功后,后端会建立关系:
user_id
device_id
bind_time
role: owner / member
从这之后,App 才能在设备列表里展示它,给它发控制命令,或者读取它的状态。
所以扫码绑定不会因为扫到了设备码就完成。扫码只是拿到设备身份,绑定关系还要由服务端确认。
五、扫码跳转时,要分清打开网页还是打开 App 页面
很多二维码只是用来跳转。
线下海报、活动物料、商品包装、分享图上,经常会放一个码。用户扫完以后,可能进 H5 页面,也可能打开 App 内某个页面。
常见形式有几种:
普通网页 URL
App Scheme
Universal Link
短链
带参数的活动链接
普通网页 URL 比较好理解,扫出来以后可以直接打开浏览器或 WebView。
App Scheme 是 App 自己约定的一套地址:
myapp://album/detail?id=10001
App 收到以后,可以跳到剧集详情页、会员页、活动页。
Universal Link 则常用在 iOS 上。同一个 HTTPS 链接,如果用户装了 App,可以打开 App 内页面;没装 App,就落到网页。
比如:
https://example.com/video/20001
用户装了 App,就进 App 的视频详情;没装 App,就打开 H5 详情页或下载页。
这里会遇到一个产品上很常见的问题:同一个二维码,要兼容不同设备、不同系统、有没有安装 App、有没有登录。
所以扫码跳转往往会经过一层中转:
扫到短链
↓
短链服务解析参数
↓
判断设备和 App 安装情况
↓
打开 App 页面 / H5 页面 / 下载页
App 端看到的是跳转,后面可能还有短链服务、活动系统、登录系统、内容系统在配合。
六、二维码为什么要过期、一次性使用

扫码场景里,经常会看到二维码过期。
电视登录二维码过一会儿会刷新;付款码过一会儿会变;临时支付码用过以后不能再用。
这些限制有实际原因。
二维码一旦被拍照、转发、截屏,就可能离开原来的使用场景。只要那段内容还有效,别人就可能拿着它继续请求后端。
所以很多二维码会带上:
过期时间
随机 token
使用状态
生成来源
用户或设备绑定信息
签名
后端收到扫码请求时,会检查:
这个码是否由系统生成
有没有被篡改
是否还在有效期内
是否已经用过
是否属于当前用户或当前设备
当前场景能不能使用
扫码登录里,一个 token 通常只能完成一次确认。
扫码支付里,付款信息要和订单、金额、收款方对上。
如果这些检查缺失,二维码就会从一个方便入口变成风险入口。
七、App 端容易踩的坑
移动端做扫码时,常见坑不只在相机识别。
比如扫码页面打开失败,可能是相机权限没给;识别慢,可能是光线、焦距、二维码太小;从相册识别失败,可能是图片压缩、二维码被裁掉。
这些是扫码前半段的问题。
后半段还有更多业务问题:
扫出来的内容不属于当前 App
短链已经失效
二维码已经被使用
用户没登录
登录态过期
当前用户没有操作权限
App 版本太低,识别不了新场景
跳转参数缺失
后端状态和页面展示不一致
还有一种情况很常见:同一个二维码,在不同 App 里扫,结果不一样。
微信扫一扫可能打开一个 H5;自家 App 扫,可能进入 App 内详情页;电视端登录码只能由对应 App 扫,别的工具扫出来只是一段看不懂的字符串。
这说明扫码结果本身并不等于业务结果。
谁来扫、在哪个 App 里扫、扫的时候用户是什么身份、后端如何解释这段内容,都会影响最后的结果。
八、把整条链路连起来
从用户扫到一个二维码,到业务完成,可以连成这样:
用户打开扫码
↓
App 申请相机权限
↓
相机识别二维码
↓
App 拿到一段字符串
↓
判断是 URL、token、订单码还是设备码
↓
进入对应业务流程
↓
后端校验有效期、签名、身份、状态
↓
完成登录、支付、绑定或跳转
↓
App 展示结果
移动端看到的是:
打开相机
识别二维码
解析结果
跳转页面
展示成功或失败
系统背后关心的是:
这段内容属于哪个场景
这个码是谁生成的
现在还是否有效
有没有被使用过
当前用户有没有权限
要修改哪条业务状态
失败时要给用户什么提示
扫码模块看起来只是相机识别,后面接着的可能是登录态、订单状态、设备关系和活动跳转。
App 拿到二维码内容,只是拿到了一个入口。这个入口能不能变成登录成功、支付成功或绑定成功,要看后端怎么校验、怎么消费、怎么记录状态。
夜雨聆风