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

Node.js POST路由变量不更新:在线沙龙预订系统条件校验失效

Hey there! I see exactly what's tripping you up here—Node.js's asynchronous nature is making your validation checks run before your database queries finish, and that's why they're not working. Plus, the "Cannot set headers after they are sent" error happens because you're trying to send multiple responses (like redirects) when the async callbacks fire. Let's fix this step by step.

What's Wrong with the Original Code?

  1. Async Execution Order: Your booking.find() calls are asynchronous, but the if (a === 0)/if (b === 0) checks run immediately after starting those queries. At that point, a and b are still their initial value of 1, so the validation never triggers even when there's a conflict.
  2. Multiple Response Attempts: If you tried adding res.redirect() inside the forEach loops, you'd end up trying to send a response every time a matching booking is found—once the first redirect is sent, any subsequent attempts throw the "headers already sent" error.

Fixed Code Using Async/Await (Cleaner & Reliable)

Let's rewrite the POST route using async/await to handle the asynchronous database calls properly. This way, we wait for all queries to finish before running our validation logic.

var express = require("express");
var router = express.Router();
var salon = require("../models/salon");
var comment = require("../models/comment");
var booking = require("../models/booking");
var middleware = require("../middleware/index.js");
var flash = require("connect-flash");

router.get("/booking", middleware.canMakeBooking, function (req, res) {
  res.render("booking/new.ejs");
});

// Updated POST route with async/await
router.post("/booking", middleware.canMakeBooking, async function (req, res) {
  try {
    const { salonname, date, time } = req.body;
    const bookingdate = new Date(date);
    const currdate = new Date();
    
    // Normalize dates to compare only the date part (no time)
    const normalizedBookingDate = new Date(bookingdate.setHours(0, 0, 0, 0));
    const normalizedCurrDate = new Date(currdate.setHours(0, 0, 0, 0));

    // 1. Check if selected date is valid (today or future)
    if (normalizedBookingDate < normalizedCurrDate) {
      req.flash("error", "please select a valid date!");
      return res.redirect("back");
    }

    // 2. Find the salon by name
    const foundsalon = await salon.findOne({ name: salonname });
    if (!foundsalon) {
      req.flash("error", "no such salon");
      return res.redirect("back");
    }

    // 3. Check for existing bookings: both user's and salon's on the target date
    const [userExistingBooking, salonExistingBooking] = await Promise.all([
      // Check if user already has a booking on this date
      booking.findOne({
        "client.id": req.user._id,
        date: {
          $gte: normalizedBookingDate,
          $lt: new Date(normalizedBookingDate.getTime() + 24 * 60 * 60 * 1000)
        }
      }),
      // Check if salon already has a booking on this date
      booking.findOne({
        salonName: salonname,
        date: {
          $gte: normalizedBookingDate,
          $lt: new Date(normalizedBookingDate.getTime() + 24 * 60 * 60 * 1000)
        }
      })
    ]);

    // 4. Validate conflicts
    if (userExistingBooking) {
      req.flash("error", "you have already made a booking for this day");
      return res.redirect("/salons");
    }
    if (salonExistingBooking) {
      req.flash("error", "a booking for this day is already made by someone at this salon");
      return res.redirect("/salons");
    }

    // 5. Create the new booking if no conflicts
    const newbooking = {
      salonName: salonname,
      date: date,
      client: { id: req.user._id, username: req.user.username },
      madeon: Date.now()
    };
    await booking.create(newbooking);
    
    req.flash("success", "booking done!");
    res.redirect("/salons");

  } catch (err) {
    console.error(err);
    req.flash("error", "Something went wrong with your booking.");
    res.redirect("/salons");
  }
});

router.delete("/booking/:id", middleware.canMakeBooking, async function (req, res) {
  try {
    await booking.findByIdAndRemove(req.params.id);
    req.flash("success", "booking deleted"); // Fixed typo: added flash type
    res.redirect("back");
  } catch (err) {
    console.error(err);
    req.flash("error", "Failed to delete booking.");
    res.redirect("back");
  }
});

module.exports = router; // Don't forget to export the router!

Key Improvements:

  • Async/Await: Makes the code linear and easy to follow, ensuring we wait for database queries to complete before moving on.
  • Promise.all: Runs both booking checks in parallel instead of sequentially, making the process faster.
  • findOne Instead of find: Stops searching as soon as a conflicting booking is found, which is more efficient than fetching all bookings and looping through them.
  • Date Range Query: Uses MongoDB's $gte and $lt to check for bookings within the target day, which is more reliable than manually comparing dates in code.
  • Proper Error Handling: Wraps everything in a try/catch block to handle unexpected database errors gracefully.
  • Fixed Typo: In the delete route, you had req.flash("booking deleted")—missing the flash type (like "success"), which would cause issues.

This should resolve both the validation not working and the "headers already sent" error. Let me know if you run into any other issues!

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.09 17:07:34