You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JS静态类如何调用静态方法?Express控制器报错解决

报错核心原因
  1. Express 路由注册控制器方法时,类实例方法的this上下文默认会丢失,直接调用router.xxx('/path', controller.add)时,方法内部的this会变成undefined,自然无法读取getRequestValues方法。
  2. 原代码存在多处逻辑缺陷:
    • 调用异步方法getRequestValues时没有加await,会导致异步逻辑还没执行完就走后续判断
    • delete方法调用getRequestValues时没有传入req参数,根本拿不到请求数据
    • 使用类静态字段存储请求级数据存在严重并发问题:Node.js 单线程模型下,多个同时进来的请求会互相覆盖静态字段的值,导致A用户的操作改到B用户的购物车数据
    • 部分变量引用缺少this前缀(比如basket.id直接写basket,会触发未定义报错)
    • 删除商品时查询条件只传了deviceId,会跨用户删除其他人购物车的同ID商品

符合DRY原则的正确实现

不要用静态字段/实例属性存储请求级数据,抽离的公共方法直接返回解析后的上下文数据,同时做好this绑定即可。

修复后的控制器代码

const {Basket, BasketDevice, Device} = require('../models/models')
const ApiError = require('../error/ApiError')

class BasketController {
    // 抽离公共解析逻辑,纯异步方法直接返回结果,不依赖全局/类级存储
    async getRequestData(req) {
        const {deviceId, quantity = 1} = req.body
        const basket = await Basket.findOne({
            where: {userId: req.user.id},
        })
        const basketDevice = await BasketDevice.findOne({
            where: {deviceId, basketId: basket.id},
        })

        return {
            deviceId,
            quantity: Number(quantity),
            basket,
            basketDevice
        }
    }

    async add(req, res, next){
        const {deviceId, quantity, basket, basketDevice} = await this.getRequestData(req)

        if(basketDevice){
            await BasketDevice.update(
                {quantity: basketDevice.quantity + quantity}, 
                {where: {deviceId, basketId: basket.id}}
            )
        } else {
            await BasketDevice.create({deviceId, basketId: basket.id, quantity})
        }
        
        return res.json({message: `Successfully added ${quantity} units of goods`})
    }

    async getOne(req, res, next){
        const basket = await Basket.findOne({
            where: {userId: req.user.id},
            include: {
                model: BasketDevice,
                include: {
                    model: Device
                },
                attributes: ['id', 'deviceId', 'basketId', 'quantity'],
            }, 
        })    

        return res.json(basket)
    }

    async delete(req, res, next){
        const {deviceId, quantity, basket, basketDevice} = await this.getRequestData(req)

        if(!basketDevice){
            return next(ApiError.badRequest('The product in the basket is already missing'))
        }

        if(basketDevice.quantity <= quantity){
            await BasketDevice.destroy({
                where: {
                    deviceId,
                    basketId: basket.id
                }
            })
            return res.json({message: 'The product was successfully deleted'})
        }

        await BasketDevice.update(
            {quantity: basketDevice.quantity - quantity}, 
            {where: {deviceId, basketId: basket.id}}
        )
        
        return res.json({message: `Successfully deleted ${quantity} units of goods`})
    }
}

module.exports = new BasketController()

路由层写法修正

注册路由时必须绑定控制器实例的this上下文,二选一即可:

const basketController = require('./controllers/basketController')

// 写法1:箭头函数包裹(更直观,推荐)
router.post('/basket/add', (req, res, next) => basketController.add(req, res, next))
router.get('/basket', (req, res, next) => basketController.getOne(req, res, next))
router.delete('/basket/delete', (req, res, next) => basketController.delete(req, res, next))

// 写法2:手动bind this
// router.post('/basket/add', basketController.add.bind(basketController))

额外修复的原有逻辑问题
  • 新增商品首次加入购物车时默认给quantity=1,避免数据库存null值
  • 删除商品时补全basketId查询条件,避免越权删除其他用户的购物车数据
  • 删除数量大于等于商品现有数量时直接删除整条记录,避免购物车商品数量出现负数
  • 所有数据库异步操作都补全await,避免时序错误
  • 修正了返回文案的拼写错误

内容的提问来源于stack exchange,提问作者rjunovskii

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 01:48:14