“现在的面试越来越有意思了。前几天面了一个前端女生,简历写得挺漂亮,项目经验也有,结果我问到她平时怎么做点餐小程序的登录,她支支吾吾半天,最后说‘就是调接口啊’。我当时心里咯噔一下——这八成是个只会写页面、不关心业务闭环的‘熟练工’。
后来我让她具体说说,从用户打开小程序到下单成功,这中间登录状态是怎么保持的?token 存在哪?过期了怎么办?她基本答不上来。这不是她一个人的问题,我最近面了好几个年轻人,普遍对‘登录’这种最基础的业务场景缺乏整体认知。今天就把这个案例掰开揉碎聊一聊,希望对正在找工作或者带新人的朋友有点启发。”
1. 一个点单登录,到底想考什么
先说结论:面试官问“点单登录”,真不是想为难人,而是想看候选人有没有完整跑通过一个业务闭环。点单登录是前端最典型、最高频、也最能暴露基本功的场景,它至少涵盖了几个层面的能力。
第一层是协议与交互层。点单登录通常是微信小程序场景,要走微信授权、手机号快捷登录、后端换 token 这一套流程。这里要懂wx.login拿到 code,把 code 发给后端,后端再向微信服务器换取 openid 和 session_key。很多人只知道调接口,但不理解 code 为什么要一次性、为什么不能在前端直接拿 openid。实际上这涉及安全性设计,openid 一旦暴露,别人就能冒充你的身份。
第二层是状态管理层。登录成功后,token 放哪?是放localStorage、cookie还是内存变量?这直接决定了用户刷新页面、重新打开小程序时是“掉登录”还是“免登录”。点单场景非常典型:用户点了半天菜,结果结账时发现登录过期了,整个购物车全丢,这在真实业务里是会被投诉的。很多候选人压根没想过这个问题,默认 token 存在本地就行了,完全没考虑过期刷新、并发请求、多端同步这些边界情况。
第三层是业务连贯性层。点单不是“登录”一个动作就完事了。登录之后要获取用户信息、定位门店、拉取菜单、加入购物车、生成订单、支付、查看订单状态……全链路都要带着用户身份。这要求你对 HTTP 无状态、JWT 结构、请求拦截器、路由守卫这些东西有真实的工程经验,而不是刷几道面试题就过得去的。
所以面试官问“点单登录”,看着是在问一个登录功能,实际是在问:你有没有完整体验过一个真实产品从 0 到 1 的诞生过程?有没有处理过线上反馈、修过 bug?有没有思考过异常情况、用户体验?这一串问题下来,水平高低立刻见分晓。
2. 面试现场暴露的五类基本功缺失
那天面试结束后,我把整个对话复盘了一遍,发现小姑娘的问题其实出在基本功不扎实上。具体来看有五个点,我估计这也是很多初级前端共通的软肋,值得拿出来单独说说。
2.1 停留在“调接口”层面,缺乏系统思维
这是最大的问题。当我问“登录怎么实现”时,她的回答是“把 code 发给后端,后端返回 token,然后存起来”。这个回答没错,但过于单薄。我追问“存哪里”“存了之后每次请求怎么带上”“token 过期刷新怎么办”,她就答不上来了。
这本质上是对前端知识体系缺乏“系统化”理解。前端工作不是“页面 + 接口”的拼接,而是一条完整的数据流:用户操作 → 前端状态更新 → 发起请求 → 后端处理 → 返回数据 → 前端渲染 → 状态同步。每一步都有关联,每一步都可能出错,而且这才是日常工作中真正的难点。
2.2 对异步流程理解浮于表面
点单登录里有一个必考的细节:先wx.login拿 code,再让后端换 token,拿到 token 之后才能请求用户信息。这里存在严格的前后依赖关系,属于典型的“异步流程控制”。她只说“调接口”,完全没意识到这里需要处理回调嵌套、Promise 链、防重复提交等逻辑。
实际业务里,这个场景还会遇到并发问题——用户快速点击“登录”按钮两次,就可能发出两个 code 请求,而 code 是一次性的,两个请求只会成功一个,另一个直接报错。这种并发抖动的处理,没有真实开发经验的人根本想不到。
2.3 对本地存储的认知停留在“能用就行”
我特意问了 token 存哪。她想了一会儿说“localStorage”。我反问:“小程序里没有 localStorage,只有 wx.setStorageSync 或者 Storage API,你确定吗?”她愣住了。
不是说要背 API,而是说你要明白不同存储方案的差异。localStorage是浏览器层面的持久化存储,sessionStorage是会话级别的,内存变量是页面级的,小程序里又有自己的一套存储体系。每种方案都有不同的生命周期和容量限制,选型错了直接导致用户反复登录、页面崩溃。很多新人不管存什么都是 localStorage 一把梭,遇到跨域、隐私模式、多标签页同步就懵了。
2.4 完全没有异常处理意识
我问她:“如果后端返回的 token 过期了,前端应该怎么处理?” 她想了很久,说“重新登录吧”。这个答案不算错,但一看就没处理过线上问题。
真实场景是:只要用户停留在页面上时间长一点,token 就可能过期。如果前端不做拦截,就会出现“操作到一半突然所有请求报 401”的情况。好的做法是统一在请求拦截器里判断 401 错误,弹一个遮罩层提示用户“登录已过期,正在为你刷新”,后台静默续期,用户无感知地继续使用。如果暴力地直接把用户踢回登录页,购物车数据全没了,这个体验就太糟糕了。
2.5 对业务场景的“为什么”缺乏好奇心
这个是我最在意的。她做了几个项目,但每个项目都在“照着原型实现”,从没问过“为什么这个按钮要放这里”“为什么这个接口要等拿到 code 才能调”“为什么这个状态要全局维护”。
技术说到底是为业务服务的。你不理解业务,就做不出合理的架构设计,写出来的代码就是“可以跑”但“不好改”。前端面试越到后面,越考察你有没有业务 Sense,而不是单纯的 API 调用能力。
3. 一个标准点单登录的技术拆解
把上面这些教训总结一下,我干脆用一个完整的点单登录流程来当例子,给新人们一个可以直接对照复习的版本。这部分的逻辑,我在实际项目里已经验证过很多次,整体是比较稳的一套方案。
3.1 整体流程梳理
从用户进入点单小程序开始,大致是这样一个链路:
- 用户在微信里打开小程序,前端拿到
wx.login产生的临时 code。 - 前端将此 code 发送到后端接口,后端携带 code、appid、secret 去微信服务器换取 openid 和 session_key。
- 后端用 openid 查数据库,判断是否已有用户记录。没有则自动创建新用户。
- 后端生成自定义 token(如 JWT),返回给前端。
- 前端保存 token,并携带 token 调用“获取用户资料”接口(头像、昵称、手机号)。
- 之后的所有业务请求,前端统一在请求头里带上 token,后端据此识别用户身份。
- 后端返回 401 时,前端启动“无感刷新”机制,用 refresh_token 换取新 token,同时重放失败的业务请求。
3.2 token 的存储选型
这一步很多人栽跟头。我建议分场景看待:
- 单页应用(SPA 网页端):优先放内存变量 + 刷新后回退到
localStorage的方案。同时监听localStorage变更事件,实现多标签页同步。 - 微信小程序:放在
wx.setStorageSync持久化,进入首页时异步校验 token 有效性。 - 涉及较高安全等级的后台系统:可以用 HttpOnly cookie(或者自己项目的安全存储方案),前端读不到,靠浏览器自动携带,降低 XSS 泄露风险。
选择标准只有一个:这次登录数据是否敏感,以及被窃取之后的破坏力有多大。点单业务属于低风险应用,token 放 Storage 没什么大问题,但要有过期续期机制。金融、支付类的高风险应用,必须满足更严格的存储规范,这就要做专门的安全评估了。
3.3 请求拦截与无感刷新
无感刷新是实现“用户挂着页面一直点单不会掉线”的关键。
我的做法是:在请求封装层维护一个isRefreshing标记。当某个请求返回 401 时,先检查是否已经在刷新 token,如果不在,就发起刷新请求,同时把失败的业务请求放进一个队列里。刷新成功之后,用新的 token 把队列里的请求重新发送一遍。这样一来,对整个业务层来说,用户完全无感知。
这里有个细节:多个请求同时返回 401 怎么办?如果每个请求都发一次刷新请求,那并发量一大,后端就要炸。所以要用单例模式,保证同一时间只有一个刷新请求正在执行,其余请求全部排队等通知。这也是面试官很爱考的“并发截流”思路。
3.4 开放服务(微信能力)的注意点
微信点单还有一个特有的点:用户手机号。现在微信不允许前端直接拿手机号,必须通过“手机号快速验证组件”结合后端能力来获取。具体流程是:用户点击授权 → 拿到动态 token → 后端再用这个 token 去微信服务器换手机号。
很多新人不知道这个限制,还按老一套做法,让前端直接传 input 里的手机号,这样往往会被平台规则卡住。真正理解这套逻辑的人,会把“获取手机号”设计成独立服务模块,调用一次后把手机号与用户绑定,后续下单不用再次验证。
4. 前端新人如何系统补强这类基本功
挂了几个候选人之后,我也一直在想一个问题:学校或者培训班其实不太教这些东西,一个刚入行的新人,怎么才能把这类基本功补上?我自己总结了三条比较管用的路径。
4.1 找一个真实项目从头到尾跑一遍
这是最有效的办法。不是照着网上的教程抄代码,而是自己给自己定一个完整需求,比如“做一个小程序点单系统”。从注册服务账号、配置服务器、设计数据库、写后端接口到前端页面联调、部署上线,一步不落走一遍。
为什么要强调“完整”?因为只有自己踩过一遍坑,你才知道 code 换 openid 的流程为什么这样设计,才知道 token 为什么会有过期时间,才知道部署到线上之后用户访问为什么会变慢。这些经验不是看文档能得来的,必须亲手做才能长记性。
4.2 养成“换位思考”的排查习惯
遇到一个报错,不要急着改代码,先问自己三个问题:这个报错是在什么场景下出现的?用户走到这一步之前做了什么操作?后端返回的数据完整吗?
我前面提到的小姑娘,大概率是没怎么做过“线上问题排查”的。真正常年在生产环境摸爬滚打的人,一出问题就有肌肉记忆,会去看控制台网络面板的请求状态码、去比对接口文档的返回结构、去复现用户的操作路径。这套“排查思路”比会写多少代码都重要。
4.3 补全 HTTP 和前端工程化的知识拼图
很多人写了好几年前端,说自己会fetch、会axios,但对 HTTP 状态码、请求头、响应头的理解还是半吊子。这其实是不行的。点单登录涉及到的 token 传递、401 判断、请求重放,全部建立在对 HTTP 协议的准确理解之上。
建议新手把几个核心知识点彻底啃透:HTTP 无状态是什么意思、常见状态码的语义、JWT 的结构和校验方式、Cookie 与 Storage 的区别、跨域问题的成因。这些内容不算前沿,但属于“地基中的地基”,把这块补齐,你在面试时谈吐都能自信很多。
5. 作为面试官,我到底在评估什么
写了这么多,最后聊回面试本身。作为面试官,当一个候选人坐在对面,我手里拿着的其实不是一份简历,而是一张“潜力评估表”。我关注的不是你有没有做过点单,而是:
- 遇到一个不熟悉的需求,你能不能拆解成技术方案?
- 遇到线上故障,你有没有一套完整的排查思路?
- 踩过一个坑,你能不能总结成可复用的经验?
- 被追问边界情况,你能不能顶住压力继续思考?
这些都是基础能力,而不是具体技术栈。技术栈可以学,项目经验可以积累,但一个工程师是否具备“把业务转化为代码”的抽象能力,才是决定他未来能走多远的关键。那个面试的小姑娘,最后我没录用。不是因为她答不出点单登录,而是因为她在面对一连串追问时,把“不会”写在了脸上,没有任何尝试自救的迹象。
我希望每一个正在准备面试、或者正在带新人的朋友都能从这个案例里看到点什么。不怕你不会,就怕你停在“会调接口”的舒适区里不再往前探索。面试不是一场表演,是你向面试官展示自己解决未知问题能力的机会。基础薄没关系,意识到问题,动手去补,下一个面试肯定能打一个漂亮的翻身仗。
你在面试里遇到过类似的候选人吗?或者你自己就曾在登录状态这种基础问题上栽过跟头?欢迎在评论区分享一下你或你团队针对登录的实现方案。