因此,我最近try 创建一个预订网站,您可以在其中 Select 您希望预订的日期.然后向/api/v1/reserve发送请求,判断数据是否有效.生成条带支付意图,将预订保存到数据库,并将支付意图id发送到前端(用于确认).我的问题是,如果两个客户同时单击"发送",他们都会为不应该发生的相同日期付款.

router.post("/reservation", async (req, res) => {

    //Check if everything is in the reqest
    if (!req.body?.name || !req.body?.phone || !req.body?.date) return res.sendStatus(400);
    if (!req.body.phone.match(/^[+]{0,1}[4]{1,2}[8][\s0-9]*$/)) return res.status(400).json({
        type: ErrorTypes.PHONE
    });


    //Validating date
    const reservationDate = new Date(req.body.date);
    if (reservationDate < new Date()) return res.status(400).json({
        type: ErrorTypes.DATE
    });
    //Checking if date is already reserved
    if (await checkIfDateReserved(reservationDate)) return res.status(400).json({
        type: ErrorTypes.RESERVED
    })
    //if reservation date is weekend raise the price ????
    const estimatedPrice = reservationDate.getDay() == 6 || reservationDate.getDay() == 0 ? 3500 : 2000;
    try {
        //Create payment intet
        const intent = await stripe.paymentIntents.create({
            amount: estimatedPrice,
            currency: "PLN",
            payment_method_types: ['card']

        });

        const document = new ReservationModel({
            name: req.body.name,
            reservationDate: reservationDate,
            phone: req.body.phone,
            complete: false,
            intentId: intent.id
        });
        await document.save();
        //If everything went smoothley, send the secret to the client
        //Send the client the intent secret to confirm the payment
        res.json({ clientSecret: intent.client_secret });


    } catch (error) {
        res.status(500);
    }

});

基本上,这两个进程在不同的线程中并行运行,它们判断日期是否同时保留,并同时保留.如何使数据库在处理另一个保存请求之前等待第一个保存请求完成?reservationDate字段是唯一的,但MongoDB似乎仍然忽略了它.

另外,我也想过使用事务处理,但我真的不知道它们在这里如何apply.

推荐答案

所以我最后用了this道题的答案,多亏了0x1C1B.互斥最终工作得很好.如果有人需要,留下代码.

const mutex = new Mutex();

router.post("/reservation", async (req, res) => {

    //Check if everything is in the reqest
    if (!req.body?.name || !req.body?.phone || !req.body?.date) return res.sendStatus(400);
    if (!req.body.phone.match(/^[\s0-9]{9,11}/)) return res.status(400).json({
        type: ErrorTypes.PHONE
    });


    //Validating date
    const reservationDate = new Date(req.body.date);
    if (reservationDate < new Date()) return res.status(400).json({
        type: ErrorTypes.DATE
    });
    await mutex.lock(); //Lock the mutex to avoid processing two reservations at once
    //Checking if date is already reserved
    if (await checkIfDateReserved(reservationDate)) {
        mutex.release(); //Release the mutex so other requests can continue
        return res.status(400).json({
            type: ErrorTypes.RESERVED
        })
    }
    //if reservation date is weekend raise the price ????
    const estimatedPrice = reservationDate.getDay() == 6 || reservationDate.getDay() == 0 ? 3500 : 2000;
    try {
        //Create payment intet
        const intent = await stripe.paymentIntents.create({
            amount: estimatedPrice,
            currency: "PLN",
            payment_method_types: ['card']

        });

        const document = new ReservationModel({
            name: req.body.name,
            reservationDate: reservationDate,
            phone: req.body.phone,
            complete: false,
            intentId: intent.id
        });
        await document.save();
        //If everything went smoothley, send the secret to the client
        //Send the client the intent secret to confirm the payment
        res.json({ clientSecret: intent.client_secret }); //Send the client_secret required for payment confirmation
        //If the confirmation doesn't go through in 5 minutes the reservation is canceled due to "createdAt" field in the schema (see ../../schemas/Reservation.ts)
        //If the payment goes through the automatic deletion is cancelled (see index.ts:59)
        mutex.release(); //Release mutex after reservation has been saved to db
        //So other users can't reserve it

    } catch (error) {
        res.status(500);
        mutex.release();
    }

});

Node.js相关问答推荐

在渲染上部署Node.js服务器时出错:MODULE_NOT_FOUND

Node.js PNG缓冲区获取未知图像格式错误

用于SLACK命令返回json而不是文本的AWS lambda函数

ForbidenError:使用Express.js的CSRF令牌无效

在mongoose虚拟属性中处理异步操作

如何设置 Puppeteer Select 器的唯一性?

错误:无法为 /blog 收集页面数据并且在 object.fetch 处获取失败

Jest - SyntaxError: 不能在@nestjs/axios 的模块外使用 import 语句

图像存储在后端文件夹中,但使用 multer 和 react.js 在前端找不到

TypeError:changeChecked 不是函数

cURL 和 shell 任务

如何在 cypress 测试中进行计算

如何在 mongoDB 中进行全动态搜索?

如何为 node.js 服务器分配域名?

如何使用 Node.js 将 base64 编码图像(字符串)直接上传到 Google Cloud Storage 存储桶?

如何在 Joi 字符串验证中使用枚举值

用一级 try ... catch 捕获 JavaScript Promise 中的错误

如何在离线时安装 npm 包?

Bootstrap 中的 Grunt 依赖冲突

NodeJS:如何调试检测到 EventEmitter 内存泄漏.添加了 11 个侦听器