乡镇外卖先做小程序还是App,应先按顾客入口与工作端分工选组合;若两入口共存,需要防同一购买请求跨端重试时生成两张订单。下面用可信身份映射、业务请求号和内容绑定实现这个局部约束,作为增设App前的验收示例。
微订官网外卖跑腿方案列有公众号、小程序、App等入口,以及商家、骑手、平台多角色端口。这是第一方产品类别说明,可据此核对乡镇项目的端口组合;具体套餐、账号互通、通知方式和设备支持仍要按实际版本演示。
构造用户在小程序提交后未看到响应,随后切App恢复原请求。相同业务身份与请求应得到原订单;主动再购买要用新请求。示例不包含真实登录、支付与部署,不代表微订内部实现。
对象 | 约束 | 作用 |
|---|---|---|
identities | 渠道和外部身份映射到可信业务用户 | 示例只预置两个已绑定身份 |
receipt key | 业务用户加请求号唯一 | 跨端重试沿同一购买意图 |
payload | 商家与整数分金额固定 | 同号改内容拒绝 |
order | CREATED保存来源入口 | 新增入口不改变原订单身份 |
依赖Node.js内置node:assert/strict,无第三方包。保存为entry.cjs并运行node entry.cjs。Map只用于单进程演示;外部身份到业务身份的认证绑定不在实现范围,不能把请求里自报的身份当作已认证身份。
const assert=require('node:assert/strict');
// Local core example only. Authentication and durable transactions are omitted.
const identities=new Map([['mini:U7','U1'],['app:A9','U1']]);
const receipts=new Map();
function create(channel,external,request,merchant,total){
const user=identities.get(channel+':'+external);
if(!user)throw Error('IDENTITY_UNBOUND');
if([request,merchant].some(x=>typeof x!=='string'||!x||x.includes(':'))||!Number.isSafeInteger(total)||total<0)throw Error('INVALID_INPUT');
const key=user+':'+request,payload=JSON.stringify([merchant,total]);
if(receipts.has(key)){
const old=receipts.get(key);if(old.payload!==payload)throw Error('REQUEST_CONFLICT');
return {...old.order};
}
const order={id:'O'+(receipts.size+1),user,merchant,total,originChannel:channel,state:'CREATED'};
receipts.set(key,{payload,order});return {...order};
}
const first=create('mini','U7','R1','M1',2000);
assert.deepEqual(create('app','A9','R1','M1',2000),first);
assert.throws(()=>create('app','A9','R1','M1',2100),/REQUEST_CONFLICT/);
assert.throws(()=>create('app','unknown','R1','M1',2000),/IDENTITY_UNBOUND/);
assert.throws(()=>create('mini','U7','R2','M1',-1),/INVALID_INPUT/);
assert.equal(create('app','A9','R2','M1',2000).id,'O2');
assert.equal(receipts.size,2);
console.log(JSON.stringify({first,orders:receipts.size,checks:['cross-channel-retry-same-order','changed-total-rejected','unbound-rejected','negative-rejected','new-request-new-order']}));mini/U7使用R1、M1、2000分生成O1。app/A9使用相同R1与内容时返回同一O1,来源仍为mini;改成2100分触发REQUEST_CONFLICT。未绑定身份触发IDENTITY_UNBOUND,负金额触发INVALID_INPUT;主动使用R2则生成O2。金额是测试输入,不是产品报价。
本版本在v24.18.0、Windows本地执行exitCode=0,最终订单数2。代码SHA-256:5ac230cbd01569e8720c756a66b5596c3cd7193a44ff56addfe5ff458515de2c。这只验证构造示例,不是产品、客户或云环境实测。
多实例应使用事务数据库,唯一键包含业务用户与请求号;原请求内容及订单同事务持久化,唯一冲突后读原记录并比较内容。请求号应跨重试可靠保存,不能每次页面打开就重新生成,否则无法表达原购买意图。
真实金额来自服务端可信商品与优惠规则;不能照搬示例让客户端决定应付金额。账号绑定需要认证证明及冲突处理,注销、解绑、跨商家权限与退款另设流程。消息失败时先查原受理状态,不再建第二订单来补通知。
如果顾客主要从微信进入,可先验证该入口;增加App时,用同身份同请求、同号异内容与未绑定身份三组输入复测。这里只覆盖跨端建单约束,不能替代商家骑手工作端、终端权限、性能或维护验收,也不能据本地通过决定整套方案已合格。
作者:微订(上海逊柯计算机科技有限公司)。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。