Node.js Express购物车总价计算返回多个异常数值解决方案
问题现象
购物车总价返回多个异常数值,相关页面截图参考:我的购物车
问题初步判断出在商品数量与商品单价相乘的金额计算环节。
关联代码
Cart.js路由实现代码
router.post("/cart", Auth, async (req, res) => { const owner = req.user._id; const { itemId, quantity } = req.body; try { const cart = await Cart.findOne({ owner }); const item = await Item.findOne({ _id: itemId }); if (!item) { res.status(404).send({ message: "item not found" }); return; } const price = item.price; const name = item.name; //If cart already exists for user, if (cart) { const itemIndex = cart.items.findIndex((item) => item.itemId == itemId); //check if product exists or not if (itemIndex > -1) { let product = cart.items[itemIndex]; product.quantity += quantity; cart.bill = cart.items.reduce((acc, curr)=>{ let cur = curr.cost.match(/\d./g).join('') return acc + Number(cur); }, 0) cart.items[itemIndex] = product; await cart.save(); res.status(200).send(cart); } else { cart.items.push({ itemId, name, quantity, price }); await cart.save(); res.status(200).send(cart); } } else { //no cart exists, create one const newCart = await Cart.create({ owner, items: [{ itemId, name, quantity, price }], bill: parseInt(quantity * price), }); return res.status(201).send(newCart); }}});
Cart数据模型
参考截图:Cart.js Model
排查思路
- 核对各分支计算逻辑一致性:当前代码新建购物车、购物车追加已有商品、购物车添加新商品三个操作分支的总价计算规则完全不统一,是核心异常来源
- 校验正则提取金额的逻辑合理性:现有代码使用
/\d./g正则从curr.cost字段提取数值,正则未做转义、匹配规则模糊,极易提取到错误字符导致转换后的数值异常 - 检查字段引用匹配度:添加新商品分支存入items的价格字段为
price,计算总价时读取的却是cost字段,字段名不匹配会直接导致取值为undefined,计算结果返回NaN - 检查分支逻辑完整性:购物车已存在、添加全新商品的分支仅做了商品列表追加,完全没有重算总价的逻辑,会导致总价始终停留在修改前的旧值
可行解决方案
- 抽离统一的总价计算方法,所有修改购物车的分支都调用同一套逻辑计算总价,禁止不同分支单独写计算规则,避免逻辑不一致
- 废弃正则解析金额的错误写法,商品价格、购物车总价字段统一使用Number类型存储,直接做数值运算,从根源避免字符串解析带来的异常
- 统一购物车子项的价格字段命名,存储、读取全程使用同一字段名,禁止混用
price、cost两种命名 - 补全所有商品修改分支的总价更新逻辑,只要对购物车商品列表做了增、改操作,都必须重新计算总价后再执行存储操作
- 金额计算增加浮点数精度处理,可参考如下统一计算逻辑:
/** * 统一计算购物车总价 * @param {Array} items 购物车商品列表 * @returns {Number} 购物车总价 */ const calcCartTotal = (items) => { return items.reduce((sum, goods) => { // 单价*数量累加,结果保留2位小数,规避浮点数精度误差 return sum + Number(goods.price) * Number(goods.quantity) }, 0).toFixed(2) }
具体修改点:
- 已有商品数量累加分支:替换原有正则匹配计算的逻辑,调用
calcCartTotal(cart.items)为cart.bill赋值 - 已有购物车添加新商品分支:商品push进items数组后,同样调用
calcCartTotal更新cart.bill,再执行save操作 - 新建购物车分支:调用
calcCartTotal计算初始bill值,替换原有单独写的parseInt(quantity * price)逻辑 - 若业务对金额精度要求高,可将所有金额字段改为以「分」为单位的整数存储,计算完成后再转换为元单位展示,彻底规避浮点数运算误差
内容的提问来源于stack exchange,提问作者Kassio
相关产品推荐
相关产品推荐

