怎么用 这是格式与深度的参考,不是让你照抄的模板。数字全部是示例,直接抄进简历一问就穿——必须换成你自己的真实数据,而且要能说清是怎么测出来的。下面每个模块都有「数字是怎么测的」和「面试追问」两段,写不出那两段的模块就不要往简历上写

面试题库(电商 / 短视频 / 社区 / 本地生活 / 旅游 / 企业服务 多业务场景)

项目背景设定 即时配送的骑手端,uni-app 打包成 App(小程序端只做查看不做履约,原因见模块一)。使用者是骑手,使用环境极端:全程在移动中、单手操作、经常戴手套、地下车库和电梯里没网、手机电量是刚性约束、一天连续用四五个小时。
为什么选这三个模块 骑手端是整个题库里唯一一个「用户在移动中且不看屏幕」的客户端。它的难点不是界面复杂度,而是三件在别的客户端不会遇到的事:后台还要持续定位(各端能力差异巨大,且和耗电直接冲突)、操作必须在弱网下不丢不重(骑手不会为了等网络停在路边)、要和第三方导航来回切换还保持状态正确

模块一:后台持续定位与上报

  1. 后台持续定位与上报(保活与降耗 + 自适应频率 + 弱网补传)★★★
    简历这样写 骑手端后台定位与上报链路(uni-app + 原生后台定位插件 + 自适应采集频率 + 本地队列补传 + 前台服务通知):配送中开启后台持续定位,采集频率按骑手状态与移动情况自适应(配送中密、静止降频、空闲低频),并在客户端做位移与精度预过滤减少无效上报;弱网时位置点入本地队列按事件时间排队,恢复后合并补传;对定位权限与后台限制做按端分级的能力声明与降级提示。连续 4 小时配送时段内后台定位在主流 Android 机型上可稳定存活,客户端预过滤使上报量下降到原来的三分之一上下,断网 10 分钟后恢复的位置点完整补传且不覆盖最新位置
    展开完整拆解
    为什么要这么设计

    这个模块要先说清一件事:「后台持续定位」在不同端上的能力差异是根本性的,不是优化程度的差异。

    第一版是按小程序做的,因为骑手不用装 App 门槛低。上线后发现压根不可行——小程序切到后台后定位基本停止,骑手一锁屏或者切去看导航,位置就断了。而位置断了的后果很严重:派单查不到他、用户看不到骑手在哪、配送距离算不出来(影响骑手收入)。所以最终结论是履约必须用 App,小程序端只保留查看功能。这个结论本身就是这个模块最重要的产出。

    换成 App 之后,剩下三个真实问题。

    一是后台定位会被系统回收。Android 各厂商的后台策略差异极大,不做保活的话骑手放兜里十几分钟位置就断了。而保活手段用得过激又会被应用市场判定为流氓行为。

    二是耗电。骑手一天连续跑四五个小时,如果我们的应用把电耗光,他就会直接关掉后台定位甚至卸载。耗电对骑手是刚性约束,不是体验问题。

    三是弱网下位置点丢失。地下车库、电梯、老旧小区,断网是常态。上报失败如果直接丢弃,那段轨迹就没了,而轨迹是配送距离结算的依据,丢了就是骑手收入算少

    所以三个设计:用系统认可的方式保活(前台服务加持续通知)自适应频率加客户端预过滤降耗位置点入本地队列保证不丢

    整体链路
    按端的能力分级(先讲清边界,再谈实现) │ ├─ App(Android) 可后台持续定位 │ 需要:前台服务 + 常驻通知栏(系统认可的合法方式) │ 需要:引导用户关闭电池优化 / 允许自启动 │ 各厂商差异大,要做机型适配引导页 │ ├─ App(iOS) 可后台定位,但必须申请「始终允许」权限 │ 系统会定期提醒用户「某应用在后台使用了定位」 │ → 要在申请时说明用途,否则用户会关掉 │ └─ 小程序 后台基本无法持续定位 → 结论:履约功能不做在小程序端,只做查看 这不是「优化不到位」,是平台能力边界 采集与上报(客户端就要减量) │ ├─ 频率按状态自适应 │ 空闲待接单 30 秒 │ 去取货 10 秒 │ 配送中 5 秒 │ 静止超过阈值 降到 30 秒(在等餐或休息) │ ├─ 客户端预过滤(在上报之前就丢掉无效点) │ 位移小于阈值 不上报(等餐时几乎不产生上报) │ 精度差于阈值 不上报(明显不可信的点) │ 与上点速度异常 不上报(本地也挡一层漂移) │ ├─ 每个点带「采集时间戳」(不是上报时间) │ 这是服务端判定新旧的唯一依据 │ └─ 批量上报:攒几个点一起发,减少请求数 但配送中的最新点要尽快发(用户在看) 弱网下的本地队列 │ ├─ 采集到的点先入本地队列(持久化,不只在内存) │ ├─ 上报成功 → 出队;失败 → 保留并退避重试 │ ├─ 队列有上限,超出丢弃最旧的低价值点 │ 优先保留:状态变更时刻的点、拐点、时间跨度均匀的点 │ → 保证轨迹形状可还原,而不是保留连续一段再断一大截 │ ├─ 网络恢复 → 合并补传(一次请求带多个点) │ └─ 服务端按采集时间戳处理 比当前最新点旧的 → 只入轨迹,不更新实时位置 (否则用户会看到骑手在地图上退回去) 耗电控制(骑手的刚性约束) ├─ 静止时降频是最有效的一项(等餐时间占比不小) ├─ 不用高精度模式跑全程,只在关键节点(到店判定)临时提精度 ├─ 网络请求合并,减少射频唤醒次数 ├─ 收工后主动停止后台定位(不能靠用户自己关) └─ 应用内展示「本次在线时长与定位状态」,让骑手对耗电有预期
    分步拆解
    1. 先确认平台能力边界,再决定功能放在哪个端。小程序后台无法持续定位,这是平台限制不是实现问题。所以履约功能必须放 App,小程序只做查看能识别出「这个需求在这个端上做不了」并推动改变方案,比硬做出一个不稳定的功能有价值得多。
    2. Android 保活要用系统认可的方式:前台服务加常驻通知。这是官方允许持续定位的途径,代价是通知栏一直有一条通知。不要用那些绕过系统限制的野路子——会被应用市场下架,而且新系统版本一升级就失效。
    3. 各厂商的电池优化要做引导。同样的代码在不同品牌手机上表现差别很大。做法是按机型给出针对性的设置引导页(教用户关闭电池优化、允许自启动),并且检测到定位异常中断时提示他去检查设置。
    4. iOS 申请「始终允许」定位权限时必须说明用途。系统会定期提醒用户「某应用在后台使用了定位」,如果用户不理解为什么,就会关掉。在申请前用自定义页面说清「用于配送过程中的位置上报和距离结算」。
    5. 客户端预过滤是降耗和减量的关键一步。位移小于阈值不上报、精度太差不上报、速度异常不上报。骑手在店里等餐的十几分钟几乎不产生上报,这一项贡献最大。
    6. 每个位置点必须带「采集时间戳」而不是上报时间。补传的点是过去采集的,服务端要靠这个时间戳判定新旧。用上报时间会导致旧点覆盖新位置。
    7. 本地队列必须持久化,不能只在内存。应用被系统杀掉或者崩溃,内存里的点就没了。而轨迹是骑手收入结算的依据,丢了是实际损失。
    8. 队列超上限时的丢弃策略要保证「轨迹形状可还原」。不能简单丢最旧的——那会导致轨迹前半段连续、后面断一大截。做法是优先保留状态变更时刻的点、路径拐点、以及时间上分布均匀的点,让稀疏后的轨迹仍能还原大致路径。
    9. 静止降频比任何其他优化都有效。骑手等餐、等电梯、休息的时间在整个在线时长里占比不小,这段时间位置不变,5 秒一次和 30 秒一次的耗电差别很明显
    10. 收工后必须主动停止后台定位。不能指望骑手自己去关。「下班还在被定位」既是耗电问题也是隐私问题,会引发投诉甚至举报。
    关键决策与取舍

    「履约功能只做 App」是这个模块最重要也最容易被质疑的决策。产品一定会问「为什么不做小程序,骑手不用装」。答案是小程序后台无法持续定位,而位置断了会导致派不到单、用户看不到骑手、配送距离算不出来(骑手收入受损)。硬做的结果是「功能看起来有,实际不可用」,比不做更糟。我保留了小程序端的查看功能(看今日单量、收入、通知),把履约操作放 App,这是折中。

    保活和「不当流氓应用」之间必须选合规的一边。有很多绕过系统限制的保活手段,短期有效但会被应用市场判定为违规,而且系统版本一升级就失效,维护成本极高。用前台服务加常驻通知虽然会在通知栏留一条,但它是长期可靠的。代价是要向骑手解释这条通知是干什么的。

    上报频率和位置精度是直接冲突的。频率低省电但用户看到的位置滞后、配送距离算得粗;频率高准但耗电。我们的取舍是按状态分档而不是全程用同一个频率——配送中(用户在看、距离要算准)用高频,空闲和静止时用低频。这个「按场景分配资源」的思路比统一调参更有效。

    踩过的坑:队列丢弃策略只丢最旧的,导致轨迹断了一大段。骑手在信号差的区域跑了 20 分钟,队列满了,程序按「先进先出」丢弃最旧的点,结果保留下来的是最后几分钟的密集点,前面 15 分钟完全空白,配送距离算出来只有实际的一小部分,骑手投诉收入算少。修法是改成按价值丢弃:状态变更点、拐点、时间分布均匀的点优先保留。教训是:数据丢弃策略必须服务于「数据的用途」——轨迹的用途是还原路径,所以要保形状而不是保连续。

    踩过的坑二:补传的旧点覆盖了实时位置。和服务端那边是同一个坑的两面——客户端补传时把队列里的点按顺序发,服务端按接收顺序处理,最后写入的是最早采集的点,用户看到骑手在地图上退回去了。客户端侧的修法是上报时明确标注这是补传批次,并按采集时间升序排列;服务端侧按采集时间戳判定。两端都要处理,只改一边不够可靠。

    没做的部分:没做基于运动传感器的定位优化(用加速度计判断骑手是否在移动,静止时完全停止 GPS)。这能进一步省电,但需要原生开发且各端传感器接口差异大,当时用「连续位置点位移判断静止」近似替代。

    数字是怎么测的

    「后台定位 4 小时稳定存活」怎么测:真机长时间跑——选几个主流机型(不同品牌,因为厂商策略差异大),开启后台定位后锁屏放置四小时,期间检查服务端收到的位置点是否连续、有无长时间空缺必须报机型和系统版本,因为这个结论高度依赖厂商实现;也要如实说明「部分机型需要用户手动关闭电池优化才能稳定」。

    上报量下降:对比开启客户端预过滤前后,同一段真实配送路径产生的上报点数。降到三分之一上下。要说明这个比例高度依赖场景——等餐时间长的订单降幅大,全程骑行的订单降幅小。给一个范围比给一个精确数字诚实。

    耗电:用系统的电量统计看应用在一段固定时长内的耗电占比,对比优化前后。这个数字受机型和其他应用影响很大,所以要在同一台设备同一条件下对比,而且要说明测试条件(屏幕是否常亮、是否同时开着导航)。

    弱网补传完整性:构造场景——开飞行模式 10 分钟并持续移动(模拟器或真机步行),恢复网络后检查服务端收到的点数与客户端采集的点数是否一致、顺序是否正确、实时位置是否是最新点。这是个可精确验证的点。

    不要报「定位成功率 99%」。定位成功率主要由设备、环境、系统决定,客户端改不了。可以报的是「因客户端原因导致的位置点丢失数」——这个是我们能控制的,而且用绝对数。也不要说「解决了后台定位问题」——iOS 和各厂商的限制是客观存在的,我们只是在规则内做到了可用。

    面试追问
    Q:骑手端为什么不做小程序?骑手不用装 App 门槛更低。 A:因为小程序后台基本无法持续定位,而这是骑手端的核心能力。小程序切到后台后定位会停止——骑手一锁屏、或者切去看导航,位置就断了。位置断了的后果很具体:派单系统查不到他(他就接不到单)、用户看不到骑手位置(投诉)、配送距离算不出来(骑手收入受损)。这不是「优化不到位」,是平台能力边界。硬做出来的结果是「功能看起来有,实际不可用」,比不做更糟。所以我们的方案是履约操作放 App,小程序端只保留查看功能(今日单量、收入、通知),既承认了限制也保留了低门槛的入口。能识别出「这个需求在这个端上做不了」并推动改变方案,比硬做出一个不稳定的功能有价值——这也是我在这个项目里觉得最重要的一个判断。
    Q:Android 后台定位老是被系统杀掉,你怎么保活? A:用系统认可的方式:前台服务加常驻通知栏。这是官方允许应用持续获取定位的途径,代价是通知栏一直有一条通知(要向骑手解释这条通知是干什么的)。明确不用那些绕过系统限制的野路子——会被应用市场判定为违规下架,而且系统版本一升级就失效,维护成本极高。除此之外还要做两件事:按机型的设置引导(各厂商的电池优化策略差异极大,同样的代码在不同品牌上表现完全不同,要教用户关闭电池优化、允许自启动,最好按机型给针对性的图文引导);异常检测与提示(服务端发现某骑手长时间没有位置上报时,通知他去检查设置)。还有一条容易忽略的:收工后必须主动停止后台定位,不能指望骑手自己关——「下班还在被定位」既耗电又是隐私问题,会引发投诉甚至举报。
    Q:骑手在地下车库跑了 20 分钟没网,这段轨迹怎么保住? A:本地队列持久化 + 按价值丢弃 + 按采集时间补传。采集到的点先入本地队列并持久化到存储而不是只在内存(应用被杀内存就没了,而轨迹是骑手收入结算依据,丢了是实际损失);上报失败保留并退避重试;网络恢复后合并补传。关键是队列满了之后的丢弃策略——我们踩过坑:早期按先进先出丢最旧的,结果保留下来的是最后几分钟的密集点,前面 15 分钟完全空白,配送距离算出来只有实际的一小部分,骑手投诉收入算少。修法是改成按价值丢弃:状态变更时刻的点、路径拐点、时间上分布均匀的点优先保留,让稀疏后的轨迹仍能还原大致路径。教训是数据丢弃策略必须服务于数据的用途——轨迹的用途是还原路径,所以要保形状而不是保连续。另外每个点必须带「采集时间戳」,补传时按时间升序发,服务端按这个时间判定新旧,否则旧点会覆盖实时位置让用户看到骑手退回去。
    Q:持续定位很耗电,骑手抱怨怎么办? A:对骑手来说耗电是刚性约束不是体验问题——手机没电他就没法接单,所以他会直接关掉后台定位甚至卸载。优化按收益排序:静止降频是最有效的一项(等餐、等电梯、休息的时间在在线时长里占比不小,这段位置不变,5 秒一次和 30 秒一次差别明显);不全程用高精度模式,只在关键节点(比如到店判定)临时提精度;合并网络请求减少射频唤醒次数;客户端预过滤(位移小于阈值不上报),既省流量也省唤醒;收工自动停止还有一个非技术但有效的做法:在应用里展示「本次在线时长与定位状态」,让骑手对耗电有预期——很多抱怨来自「不知道为什么耗电」而不是耗电本身。测耗电时要注意:同一台设备同一条件下对比,并说明是否同时开着导航(导航本身很耗电,容易被误算到我们头上)。

模块二:接单与履约操作可靠性

  1. 接单与履约操作可靠性(语音播报 + 抢单并发 + 离线操作队列)★★★
    简历这样写 接单提醒与履约操作可靠性(uni-app + 语音播报与震动 + 抢单幂等 + 离线操作队列 + 状态三态):新单提醒走语音播报加持续震动(骑手在骑行中不看屏幕),抢单提交带幂等键并由服务端原子判定归属,抢单失败给出明确原因而非笼统报错;到店、取货、送达等状态操作先入本地队列再提交,弱网下不阻塞骑手继续操作,结果分成功 / 失败 / 未知三态且未知态先查询再决定重试。压测弱网重复提交下重复接单与重复状态记录未再出现,断网期间的连续操作在恢复后按采集顺序完整补提交,新单从服务端推送到骑手听到播报约 1.5 秒
    展开完整拆解
    为什么要这么设计

    骑手端的操作场景有一个别的客户端都没有的前提:用户在移动中,而且大概率不在看屏幕。他可能正在骑车、正在爬楼、戴着手套。这个前提推翻了很多常规的客户端设计假设。

    第一版是按普通 App 做的,问题很直接。

    一是新单来了骑手不知道。只有一个界面弹窗和系统通知。骑手在骑车,手机在车架上但他在看路,等他看到已经过了接单时限,单被别人抢了或者回池重派。骑手的反馈是「你们的单我根本抢不到」。

    二是抢单的并发处理不当。广播模式下十几个骑手同时抢一单,服务端处理不及时,有骑手的界面显示「抢单成功」但实际没抢到,他骑到店里才发现单不是他的。

    三是弱网下状态操作阻塞了骑手。他到店点「已到店」,转圈半天,他不能站在原地等——但如果不等,这个状态就丢了。到取货时又点「已取货」,两个操作都在转圈。

    四是超时被当成失败,骑手重复操作。点「已送达」超时提示失败,他又点一次,服务端产生两条送达记录,后台对账时对不上。

    所以四个设计:语音播报加震动做提醒抢单归属由服务端原子判定状态操作先入本地队列不阻塞结果三态且未知先查询。后两条和支付、核销、审批是同一套模式,但骑手端多了一个约束:必须允许连续操作——不能因为上一个操作没确认就锁住下一个。

    整体链路
    新单提醒(骑手不看屏幕,所以视觉提醒是无效的) │ ├─ 服务端推送新单(长连接优先,系统推送兜底) │ ├─ 客户端收到 → 三种提醒同时上 │ 语音播报:合成语音念出关键信息 │ 「新订单,距您 800 米,配送费 6 元,请尽快接单」 │ 持续震动:不是一次,而是按节奏持续到用户响应或超时 │ 界面弹窗:全屏卡片 + 倒计时 │ ├─ 播报内容要精简且信息量足够 │ 骑手需要的是「值不值得抢」:距离、配送费、大致方向 │ 不要念完整地址(太长,骑手听不完) │ └─ 免打扰与优先级 正在骑行(速度高)时降低播报频率,避免干扰 同时多单时按价值排序,只播最优的那一单 抢单(并发归属由服务端裁定) │ ├─ 骑手点「抢单」→ 按钮立即锁定 │ ├─ 提交带幂等键(订单号 + 骑手号 + 客户端操作 ID) │ ├─ 服务端原子判定归属(Redis 原子操作 + 状态机条件更新) │ update order set rider_id = ?, status = '已接单' │ where id = ? and status = '待接单' │ 影响行数 1 → 归属确定 │ 影响行数 0 → 已被他人抢走 │ └─ 结果反馈必须明确 抢到 → 进入履约页,语音确认「接单成功」 没抢到 → 明确说「已被其他骑手接单」而不是「网络错误」 未知 → 先查该单归属,再决定显示什么 履约状态操作(先入队列,不阻塞骑手) │ ├─ 骑手点「已到店」→ 立即本地记录并更新界面(乐观更新) │ 操作入本地队列:订单号 / 目标状态 / 操作时间 / 幂等键 │ 界面上标注该状态「同步中」 │ ├─ 后台异步提交队列(串行,保证同一订单的状态按序) │ 成功 → 去掉「同步中」标记 │ 明确失败 → 标红并提示(比如「该单已被改派」) │ 未知(超时)→ 保留在队列,退避重试 │ ├─ 关键:骑手可以继续下一个操作,不被阻塞 │ 到店没同步完也能点取货 —— 两个操作按序在队列里排着 │ 这是骑手端和其他客户端最大的差异 │ ├─ 队列持久化,应用被杀重启后继续提交 │ └─ 界面上常驻显示「N 个操作待同步」 让骑手知道有东西没传上去(而不是以为都好了) 三态结果处理(和支付/核销同一套模式) ├─ 成功 → 更新状态,清幂等记录 ├─ 明确失败 → 展示具体原因,允许纠正 └─ 未知 → 不提示失败,查询该单当前状态后决定 已是目标状态 → 当作成功 仍是前置状态 → 用同一幂等键重试
    分步拆解
    1. 提醒必须是听觉和触觉的,视觉提醒对骑手无效。他在骑车看路,界面弹窗他看不到。语音播报加持续震动才是有效通道。震动要按节奏持续到用户响应或超时,一次震动很容易被忽略。
    2. 播报内容要精简到「够他做决策」为止。骑手要判断的是「值不值得抢」——距离、配送费、大致方向。不要念完整地址,太长他听不完,而且抢单阶段不需要精确地址。
    3. 骑行中要降低播报频率。速度高时频繁播报是干扰甚至安全风险。可以按当前速度调整提醒强度,这是从使用场景倒推出来的需求。
    4. 同时多单时只播最优的一单。连续播三单骑手一个也记不住。按价值(距离、配送费、顺路)排序只播第一个,其余留在界面上。
    5. 抢单归属必须由服务端原子判定。用状态机条件更新(where status = '待接单'),影响行数决定归属。客户端绝不能自己判断「我抢到了」——我们踩过界面显示成功但实际没抢到的坑,骑手骑到店才发现。
    6. 抢单失败要给明确原因。「已被其他骑手接单」和「网络错误」对骑手的意义完全不同——前者他去抢下一单,后者他会重试。笼统的失败提示会让他做错决策。
    7. 状态操作先入本地队列并乐观更新界面,这是骑手端的核心差异点。骑手不能站在原地等网络。点了就先记下来、界面先变、后台慢慢传,界面上标注「同步中」。
    8. 必须允许连续操作,不能因为上一个没确认就锁住下一个。这一点和支付、审批不同(那些场景锁住是对的)。骑手可能到店没同步完就已经取到货了,两个操作按序在队列里排着,服务端按状态机顺序处理。
    9. 队列按订单串行提交。同一订单的状态必须按序(到店在取货之前),不同订单可以并行。乱序会让服务端的状态机拒绝。
    10. 界面上常驻显示「N 个操作待同步」。骑手需要知道有东西没传上去。如果静默重试,他会以为都好了,而实际上服务端没收到,最后对账时出问题。
    11. 队列持久化并在启动时继续提交。应用被杀、手机重启,队列里的操作不能丢——它们代表已经发生的物理事实(他真的到店了、真的送达了)。
    关键决策与取舍

    乐观更新界面是必要的,但它引入了「界面和服务端不一致」的窗口。骑手看到状态已变,实际服务端还没收到。缓解手段是「同步中」标记加待同步计数,让不一致是可见的而不是隐藏的。绝对不能做的是静默乐观更新——那样骑手完全不知道有操作没传上去。

    允许连续操作 vs 锁住等确认,这里的选择和支付场景相反。支付场景锁住是对的(防重复付款);骑手端锁住会让他没法工作(站在楼道里等网络)。差异的根源是「操作是否可以在物理世界继续发生」——骑手到店和取货是真实发生的事实,系统不该阻止他记录;而支付是系统内的动作,可以也应该被约束。能说清这个差异,说明理解了业务而不是在套模板。

    语音播报的取舍:太吵和听不到之间没有中间地带。播报音量小骑手听不到(路上有环境噪音),音量大在餐厅里会引起注意甚至尴尬。做法是让骑手自己调播报音量和是否震动,并且提供「简洁播报」模式(只念「新单,6 元」)。这类和使用环境强相关的参数不要由产品拍死,交给用户调。

    踩过的坑:抢单界面显示成功,实际没抢到。早期为了响应快,客户端点击后立刻显示「抢单成功」再发请求,结果十几个骑手同时抢一单,界面都显示成功,只有一个真的抢到,其余骑手骑到店里才发现单不是自己的,白跑一趟,投诉很激烈。修法是抢单绝不做乐观更新,必须等服务端返回归属结果教训是:乐观更新只能用在「结果几乎必然成功」的操作上,竞争性操作(抢单、秒杀)绝对不能乐观。这也是为什么状态操作可以乐观(到店是既成事实)而抢单不行(归属由服务端裁定)。

    踩过的坑二:队列并行提交导致状态乱序被拒。队列里同时有「已到店」和「已取货」,并行提交,取货先到服务端,而服务端的状态机要求前置状态是已到店,于是取货被拒绝,队列里这条一直重试失败。修法是按订单串行提交(同一订单的操作排队,不同订单可并行)。顺序依赖的操作不能并行提交,这是队列设计里容易漏的一点。

    没做的部分:没做语音识别接单(骑手说「接单」就接)。骑行中动手不安全,语音交互是对的方向,但识别准确率在噪音环境下不够,误识别导致误接单的代价大,当时没做。

    数字是怎么测的

    推送到播报的时长:在服务端推送时刻和客户端播报开始时刻各打点,端到端约 1.5 秒(含长连接传输和语音合成)。要说明用的是长连接还是系统推送——两者延迟差别很大,长连接是秒级,系统推送可能几秒到几十秒(取决于系统调度)。只报长连接的数字要注明。

    重复接单与重复状态记录验证:限速模拟弱网,对同一单连点抢单 5 次、对同一状态连点 5 次,检查服务端的订单归属只有一个、状态记录只有一条。跑多轮。还要测「多骑手并发抢同一单」——用多个客户端同时抢,验证只有一个抢到且其余收到明确的「已被接单」提示。

    断网连续操作恢复验证:开飞行模式,连续点「已到店」「已取货」「已送达」,恢复网络后检查三条状态按正确顺序提交、订单最终状态正确、无重复记录。这是这个模块最该演练的场景。

    不要报「接单成功率提升」。抢单成功与否取决于其他骑手的竞争,不是客户端能决定的。可以报的是「从推送到骑手可响应的时长」(这个是我们能优化的)以及「因客户端原因导致的错误操作记录数」

    也不要报「零重复」。正确表述是「压测多轮未出现,且服务端有状态机条件更新作为第二道防线」。

    面试追问
    Q:新单来了骑手在骑车,怎么让他知道? A:视觉提醒对骑手是无效的,他在看路。所以要用听觉和触觉:语音播报念出关键信息、持续震动(按节奏持续到响应或超时,一次震动很容易被忽略)、界面弹窗只作为他低头看时的补充。播报内容要精简到「够他做决策」为止——骑手判断的是「值不值得抢」,所以念距离、配送费、大致方向,不要念完整地址(太长听不完,抢单阶段也不需要)。还有两个从场景倒推出来的细节:骑行速度高时降低播报频率(频繁播报是干扰甚至安全风险);同时来多单时按价值排序只播最优的一单,连播三单他一个也记不住。播报音量和震动开关要交给骑手自己调——路上环境噪音大需要音量高,但在餐厅里会尴尬,这类和使用环境强相关的参数不该产品拍死。
    Q:十几个骑手同时抢一单,怎么保证只有一个抢到? A:归属完全由服务端原子判定,客户端绝不能自己判断。服务端用状态机条件更新:update order set rider_id=?, status='已接单' where id=? and status='待接单'影响行数为 1 才是抢到,为 0 说明已被他人抢走。客户端提交带幂等键(订单号 + 骑手号 + 客户端操作 ID),重试不会产生第二次归属判定。我们踩过一个很痛的坑:早期为了响应快,客户端点击后立刻显示「抢单成功」再发请求,结果十几个骑手界面都显示成功,只有一个真抢到,其余骑手骑到店里才发现单不是自己的,白跑一趟,投诉很激烈教训是乐观更新只能用在「结果几乎必然成功」的操作上,竞争性操作绝对不能乐观。另外抢单失败要给明确原因——「已被其他骑手接单」和「网络错误」对骑手的意义完全不同,前者他去抢下一单,后者他会重试,笼统提示会让他做错决策。
    Q:骑手在楼道里没信号,点了「已送达」一直转圈,怎么办? A:不能让他等——骑手不会站在楼道里等网络。做法是操作先入本地队列并乐观更新界面:点了就立刻本地记录、界面状态先变、标注「同步中」,后台异步提交队列。关键的一条是必须允许他继续下一个操作——到店没同步完也能点取货,两个操作按序在队列里排着。这一点和支付、审批场景相反(那些场景锁住等确认是对的),差异的根源是「操作是否在物理世界已经发生」:骑手到店和送达是既成事实,系统不该阻止他记录;而支付是系统内的动作,应该被约束。三个配套细节:队列要持久化(应用被杀不能丢,这些是已发生的事实);按订单串行提交(同一订单的状态有顺序依赖,我们踩过并行提交导致取货先到、被服务端状态机拒绝的坑);界面上常驻显示「N 个操作待同步」,让骑手知道有东西没传上去,而不是静默重试让他以为都好了。
    Q:状态操作可以乐观更新,抢单不行,这个界限怎么划? A:看这个操作的结果是不是由竞争决定的。「已到店」「已取货」「已送达」是骑手对既成事实的记录——他真的到了,服务端几乎必然接受(除非单被改派,那是极少数情况),所以可以乐观更新,把不一致窗口用「同步中」标记暴露出来就行。「抢单」是竞争性操作,同一单有十几个人在抢,结果只能由服务端裁定,客户端乐观更新就是在猜,猜错的代价是骑手白跑一趟。同类的判断可以推广:秒杀下单、优惠券领取、库存扣减都属于竞争性操作,不能乐观;点赞、收藏、已读标记属于事实记录,可以乐观(失败了回滚显示即可)。划线的标准是「失败的概率」和「猜错的代价」——两者都低才适合乐观更新。

模块三:多单路径与导航衔接

  1. 多单路径与导航衔接(多单排序 + 第三方导航跳转 + 到点判定)★★★
    简历这样写 多单路径规划与导航衔接(uni-app + 多单顺序建议 + 第三方地图跳转与回流 + 多信号到点判定):骑手同时在手多单时给出取送顺序建议(按时限紧迫度与顺路性排序,允许骑手手动调整并记录偏差);导航走唤起第三方地图 App并处理跳出与回流后的状态恢复,各端唤起方式差异收口到能力抽象层;到店与到点不只依赖定位,用「定位 + 停留时长 + 骑手确认」多信号判定并保留人工兜底。多单顺序建议被骑手采纳的情况可观测,导航唤起失败时降级为应用内地图与地址复制,到点误判由多信号判定与人工确认兜住。
    展开完整拆解
    为什么要这么设计

    骑手很少一次只带一单,高峰期在手三到五单是常态。这带来两个第一版完全没考虑的问题。

    一是骑手要自己规划顺序,而且经常规划错。三单在手,哪个先取、哪个先送,涉及取货点和送达点交叉排列。新骑手往往按接单顺序做,结果来回折返,超时被罚。他的反馈是「你们派给我的单根本送不完」——实际是顺序不对。

    二是导航体验断裂。骑手点导航跳到第三方地图 App,导航完切回来,应用可能已经被系统回收,重新进来回到首页,他要重新找到当前订单。一趟配送要跳好几次,每次都这样。

    第三个问题更隐蔽但影响很大:到店和到点的判定。系统需要知道骑手是否真的到了(用于计算商家出餐超时、用于判定配送时长、用于纠纷)。只用定位判定不可靠——定位有几十米误差、商场里定位飘、而且定位可以被模拟软件伪造。而完全靠骑手手动点,他可能提前点(还没到就点已到店,为了避免超时)。

    所以三个设计:给顺序建议但允许骑手调整导航跳转要处理回流状态恢复到点判定用多信号而不是单一依据

    整体链路
    多单顺序建议(建议而不是强制) │ ├─ 在手单列表 → 展开成「取货点 + 送达点」的任务点序列 │ 每个任务点带:类型(取/送)、地址、时限、订单号 │ ├─ 排序依据(综合打分,不是单一维度) │ 时限紧迫度 剩余时间越少越靠前(权重最高) │ 顺路性 与当前位置和后续点的路径重合度 │ 硬约束 同一单必须先取后送(顺序不可颠倒) │ 商家出餐 预计还没出餐的取货点可以稍后 │ ├─ 界面呈现:任务点列表 + 建议顺序编号 + 地图上的连线 │ ├─ 允许骑手手动拖动调整顺序 │ → 他对路况和小区结构的了解常常超过系统 │ └─ 记录「建议顺序」与「实际执行顺序」的偏差 用于评估建议质量并反哺排序权重 导航衔接(跳出去还要能回来) │ ├─ 点导航 → 唤起第三方地图 App(骑手习惯用哪个就用哪个) │ 各端唤起方式不同(URL Scheme / 小程序跳转 / 原生 SDK) │ → 收口到能力抽象层:navigateTo(经纬度, 地址, 名称) │ ├─ 唤起前先持久化「当前上下文」 │ 当前订单号 / 当前任务点 / 页面滚动位置 │ → 这一步是回流能恢复的前提 │ ├─ 唤起失败的降级链 │ 未安装该地图 App → 换另一个 │ 都没有 → 应用内地图展示路线 │ 地图也不可用 → 展示地址文本 + 一键复制 + 一键拨号 │ └─ 回流恢复(用户从地图切回来) 监听应用切前台 → 读持久化的上下文 → 直接回到该订单页 若应用被系统回收,冷启动时也读这份上下文并跳转 → 骑手切回来就在原来的位置,不用重新找单 到点判定(多信号,不能只信定位) │ ├─ 信号一 定位距离 骑手位置与目标点的距离小于阈值 │ 阈值要按场景放宽(商场、写字楼定位误差大) ├─ 信号二 停留时长 在目标附近停留超过一定时间 │ 只是路过不算到店 ├─ 信号三 骑手确认 骑手手动点「已到店」 │ 这是主信号,前两个是辅助校验 │ ├─ 组合判定 │ 骑手点了 + 定位也在附近 → 直接通过 │ 骑手点了 + 定位不在附近 → 通过但标记异常,进风控观察 │ 定位在附近但骑手没点 → 提示他确认(不自动置状态) │ ├─ 为什么不自动置状态:骑手可能只是路过或在附近等餐 │ 自动置状态会导致配送时长和出餐超时的计算错乱 │ └─ 人工兜底 定位完全不可用(商场地下)→ 允许骑手直接确认并说明 异常确认进入运营抽查,而不是当场拦住他
    分步拆解
    1. 先把在手单展开成「任务点序列」,而不是按订单组织界面。三单在手是六个任务点(三取三送),骑手真正要决策的是这六个点的顺序。按订单展示界面会让他自己在脑子里做这个展开。
    2. 排序的最高权重是时限紧迫度,不是距离。超时是骑手最怕的(影响收入和评级)。距离只是次要因素——绕远一点但不超时,好过近一点但超时。
    3. 同一单必须先取后送是硬约束。这个约束不能被打分权重抵消,要在排序时直接保证。硬约束和软打分要分开处理,这和派单调度那边的判断一致。
    4. 顺序只做建议,必须允许骑手手动调整。骑手对路况、小区内部结构、哪个门能进的了解常常超过系统。强制顺序会让他觉得系统在碍事
    5. 要记录「建议顺序」与「实际执行顺序」的偏差。这是评估建议质量的唯一途径——如果骑手总是不按建议走,说明排序权重有问题。这个数据也能反哺派单调度的顺路计算。
    6. 导航唤起前必须持久化当前上下文,这是回流能恢复的前提。订单号、任务点、页面位置写入本地。不做这一步,应用被回收后冷启动只能回首页。
    7. 各端唤起地图的方式差异要收口到能力抽象层。URL Scheme、小程序跳转、原生 SDK 各不相同,业务层只调一个 navigateTo(坐标, 地址, 名称)
    8. 唤起失败要有完整的降级链。没装这个地图 App 换另一个、都没有就用应用内地图、地图不可用就给地址文本加一键复制加一键拨号。最后这一步很重要——骑手至少能打电话问路。
    9. 回流恢复要同时处理「切前台」和「冷启动」两种情况。应用还活着就是切前台事件,被回收了就是冷启动。两条路径都要读那份持久化的上下文,只处理一种会在另一种情况下失效。
    10. 到点判定以骑手确认为主信号,定位只做辅助校验。定位有误差、会飘、可被伪造。反过来「定位在附近就自动置已到店」是错的——骑手可能只是路过或在附近等餐,自动置状态会让配送时长和出餐超时的计算全乱。
    11. 定位与确认不一致时标记异常而不是当场拦住。骑手在商场地下定位完全不可用是常态,当场拦住他就没法工作了。做法是允许他确认并说明,异常记录进运营抽查——事后风控,而不是事前阻塞。
    关键决策与取舍

    顺序建议做成「建议」而不是「强制」,是有代价的。骑手不按建议走时,系统预估的配送时长和 ETA 就会偏离,用户看到的预计时间不准。但强制的代价更大——骑手会觉得系统不懂实际情况,抵触使用,甚至用别的方式绕过(比如提前点已取货)。取舍是接受 ETA 的偏差,换取骑手对工具的信任,同时用「偏差记录」持续改进排序质量。

    用第三方地图而不是自建导航。自建导航要接路径规划、要做转向播报、要处理离线地图,工作量巨大而且做不到第三方的水平。而骑手本来就有自己习惯的地图 App。代价是体验断裂(要跳出去再回来),所以回流恢复必须做好。「不做自己做不好的事,但要把衔接做顺」这个判断比硬做一个二流导航正确。

    到点判定的方向是「宁可放过,不可误拦」。如果判定过严(定位不在附近就不许确认到店),商场里的骑手就完全没法工作。所以放宽判定 + 事后风控抽查。反过来如果完全不校验,会有骑手远程点到店来规避出餐超时。方向的选择依据是「误拦的代价(骑手没法工作)远大于放过的代价(少数作弊被事后发现)」。

    踩过的坑:导航回来后应用回到首页,骑手要重新找单。第一版没做上下文持久化,骑手每次导航完切回来都在首页,一趟配送要重新找单三四次,他的反馈是「你们这个应用用起来很烦」。修法是唤起导航前持久化当前上下文,回流时(切前台或冷启动)读出来直接跳回。教训是:任何「跳出应用再回来」的流程都必须做上下文持久化——不能假设应用还活着,移动端的应用随时会被回收。

    踩过的坑二:定位在附近就自动置「已到店」,导致出餐超时统计全错。骑手在商圈里送另一单,路过了这家店,系统自动把状态置成已到店,于是「商家出餐时长」从那一刻开始计算,实际骑手十分钟后才真的进店,商家被误判为出餐慢。商家投诉,我们才发现。修法是自动判定只用于提示,绝不自动置状态,状态必须由骑手确认。教训是:由传感器信号自动推断的业务状态,如果会影响他方的考核或结算,就必须要人确认。

    没做的部分:没做多单路径的精确规划(考虑实际道路和实时路况的最优顺序)。目前用直线距离近似顺路性。接路径规划服务要为每种顺序组合都算一次,成本和延迟都不可接受,而且骑手的经验判断往往比算法好。

    数字是怎么测的

    顺序建议的质量:「建议顺序与骑手实际执行顺序的一致比例」这个指标比「配送时长缩短」诚实得多——后者受商家出餐、路况、骑手个人影响,归因不到排序上。一致比例低说明建议不好,高说明骑手认可。要能说出这个数据怎么采集(对比建议顺序和实际状态流转的时间顺序)。

    导航唤起与回流:报各端的唤起成功率与降级触发次数(未安装地图 App 而走降级的次数)。回流恢复要做确定性验证:跳出导航后手动杀掉应用,冷启动验证是否回到原订单页;不杀应用直接切回,验证是否回到原位置。两条路径都要测,只测一条会在另一种情况下失效。

    到点判定:「骑手确认与定位校验不一致的次数」以及其中经运营抽查确认为异常的数量。两个数一起看才有意义——不一致的大部分是定位问题(商场、地下),真正作弊的是少数。只报「拦下多少作弊」会显得判定过严,只报「不一致次数」看不出价值。

    不要报「配送超时率下降」。那受太多因素影响。也不要报「到点判定准确率 99%」——「准确」的定义需要一个已知真值的样本集,而「骑手是否真的到店」这个真值本身就很难获得。这类无法建立真值的指标不要报比率。

    面试追问
    Q:骑手同时带三单,怎么告诉他先送哪个? A:先把在手单展开成「任务点序列」——三单是六个任务点(三取三送),骑手真正要决策的是这六个点的顺序,按订单组织界面会让他自己在脑子里做这个展开。排序最高权重是时限紧迫度而不是距离(超时影响他的收入和评级,绕远一点但不超时好过近一点但超时),其次是顺路性,同一单先取后送是硬约束(不能被打分权重抵消,要在排序时直接保证)。关键是只做建议不做强制——骑手对路况、小区内部结构、哪个门能进的了解常常超过系统,强制顺序会让他觉得系统碍事,甚至用别的方式绕过。代价是他不按建议走时 ETA 会偏,我们接受这个偏差换取他对工具的信任,同时记录「建议顺序 vs 实际执行顺序」的偏差用来评估建议质量并反哺排序权重——这也是衡量这个功能好不好的唯一诚实指标。
    Q:骑手跳到高德导航,导航完切回来,怎么还在原来的订单页? A:唤起导航之前就要把当前上下文持久化(当前订单号、当前任务点、页面滚动位置写入本地存储),这是回流能恢复的前提。回流时要同时处理两种情况:应用还活着就是「切前台」事件,读上下文跳回;应用被系统回收了就是冷启动,启动流程里也要读这份上下文并跳转。只处理一种会在另一种情况下失效——我们第一版没做持久化,骑手每次导航完切回来都在首页,一趟配送要重新找单三四次,反馈是「你们应用用起来很烦」。通用教训是:任何「跳出应用再回来」的流程都必须做上下文持久化,不能假设应用还活着,移动端的应用随时会被回收。另外唤起要有降级链:没装这个地图换另一个、都没有用应用内地图、地图也不可用就给地址文本加一键复制加一键拨号(至少他能打电话问路)。
    Q:怎么知道骑手真的到店了?只看定位行不行? A:不行,定位只能做辅助校验,主信号必须是骑手确认。定位有几十米误差、商场和写字楼里会飘、而且可以被模拟软件伪造。反过来「定位在附近就自动置已到店」是明确错误的——我们踩过这个坑:骑手在商圈送另一单时路过了这家店,系统自动置成已到店,「商家出餐时长」从那一刻开始算,实际骑手十分钟后才真的进店,商家被误判为出餐慢,商家投诉才发现。所以做法是多信号组合但不自动置状态:骑手点了确认且定位也在附近就通过;骑手点了但定位不在附近则通过并标记异常进风控抽查;定位在附近但骑手没点则只提示他确认方向上是「宁可放过,不可误拦」——商场地下定位完全不可用是常态,判定过严骑手就没法工作了,所以放宽判定加事后抽查。核心教训:由传感器信号自动推断的业务状态,如果会影响他方的考核或结算,就必须要人确认。
    Q:为什么不自己做导航,而要跳第三方地图? A:因为自己做不好,而且没必要。自建导航要接路径规划、做转向语音播报、处理离线地图、应对实时路况,工作量巨大,而且做出来的水平远不如专业地图厂商——而导航体验直接影响骑手的效率和安全,做成二流是不负责的。更重要的是骑手本来就有自己习惯的地图 App,强迫他用我们的反而增加学习成本。代价是体验断裂(要跳出去再回来),所以我们把力气花在「衔接」上:唤起前持久化上下文、回流时精确恢复、唤起失败有完整降级链、各端唤起方式收口到能力抽象层。「不做自己做不好的事,但要把衔接做顺」这个判断比硬做一个二流导航正确。应用内只保留一个简单的地图展示(看路线大致走向、看骑手和目标点的相对位置),不承担导航功能。

没有匹配的内容,换个关键词试试。

项目拆解 · 骑手端(uni-app)· 共 3 个模块 · 数字均为示例,需替换成自己项目的真实数据