最近碰到个问题,就是同一个用户几乎同时的发起两次同样的请求,比如买一样东西有一定几率会出现购买两次的情况,代码逻辑判断没错,问题出在判断时序上面。下面是一段购买商品的逻辑判断:
'buyItem': async (req, res, next) => {
const itemId = req.params.itemId;
const userId = req.headers['current-user-id'];
const orderRecord = await Order.find(itemId, userId)//do mongodb search
if (orderRecord && orderRecord.status === 'paid') {//第二次请求对于这个是否购买过的判断的结果是未购买,因为第一个请求还未创建订单。
return res.status(400).json({
'code': 101,
'message': 'you have already bought it',
'result': {}
})
}
// 第一次请求执行到这里了
const orderNew = await Order.create(itemId, userId)//do mongodb create
await User.deduct(userId, item.price);
}
两次几乎同时的请求,但有一定的先后顺序,第一个请求执行到即将创建订单,但第二个请求因为第一个请求还未创建,导致判断上不符合预期。
我现在的想法是:
方法一:把创建订单放到最前面,因为 mongodb 有读写 latch,所以判断订单是否存在来决定是否进行后续操作,这样虽然能解决比较关键的路由,但并不普适。
方法二:对访问频率进行限制(rate-limit),但因为我使用了 cluster,不好做。
后端采用:node express
不知道各位大神有没有相似情况的解决方案.
加载页面的时候生成一个token,提交订单的时候一起提交,服务端接受后进行校验!
如果服务端已经处理了该token,那么抛弃当前请求;否则就处理请求