node.js - Try/catch 发送电子邮件并创建数据库条目,即使它不应该
问题描述
我有一个关于 Node.JS 中的 try/catch 的问题,在 Express 中更准确地说。我有一个销售节日、音乐会等门票的应用程序,每个活动的门票数量有限。但是,当我的服务器检测到没有剩余票证时,无论如何都会创建一个票证并发送带有票证的邮件。
app.post(
"/api/tickets",
[
body("email").trim().isEmail().isLength({ min: 8 }).normalizeEmail(),
body("firstName")
.trim()
.isString()
.isLength({ min: 2 })
.matches(/^[^0-9_!¡?÷?¿/\\+=@#$%ˆ&*(){}|~<>;:[\]]{2,}$/),
body("lastName")
.trim()
.isString()
.isLength({ min: 2 })
.matches(/^[^0-9_!¡?÷?¿/\\+=@#$%ˆ&*(){}|~<>;:[\]]{2,}$/),
body("phoneNumber")
.trim()
.isString()
.isLength({ min: 8 })
.matches(
/^((?<!\w)(\(?(\+|00)?48\)?)?[ -]?\d{3}[ -]?\d{3}[ -]?\d{3}(?!\w))$/
),
],
async (req: any, res: any, next: any) => {
try {
const errors = validationResult(req);
if (!errors.isEmpty()) {
let err = new StatusError("Error while validating body", 400);
next(err);
}
const { id, email, firstName, lastName, phoneNumber } = req.body;
let eventFound: any;
const event = await Event.findById(id, (error, result) => {
if (!error) eventFound = result;
else {
let err = new StatusError("No event found", 404);
next(err);
}
});
Ticket.find({ eventId: event?.id }, (error, tickets) => {
if (!error) {
if (event?.toJSON().maxTicketsAmount - 1 < tickets.length) {
let err = new StatusError("No tickets left", 403);
next(err);
}
} else {
let err = new StatusError("No tickets found", 404);
next(err);
}
});
const paymentIntent = await stripe.paymentIntents.create({
amount: eventFound.ticketPrice, // NEEDS TO BE ABOVE SOME VALUE!!!!!!!
currency: "pln",
payment_method_types: ["card"],
receipt_email: email,
metadata: { integration_check: "accept a payment" },
});
if (!paymentIntent) {
let err = new StatusError("Creating payment intent failed", 400);
next(err);
}
const ticket = new Ticket({
email: email.trim(),
firstName: firstName.trim(),
lastName: lastName.trim(),
phoneNumber: phoneNumber.trim(),
eventId: eventFound.id,
purchaseDate: new Date(),
});
ticket.save((error) => {
if (error) {
let err = new StatusError("Error while saving to DB", 500);
next(err);
}
});
const qr = await toDataURL(ticket.id);
console.log(ticket.id);
if (!qr) {
let err = new StatusError("Error while creating QR Code", 400);
next(err);
}
const mailTemplate = `
<h1>Hello ${firstName} ${lastName}</h1>
<p>Thanks for buying ticket for ${eventFound.nameOfEvent}, in ${eventFound.place}, taking place on ${eventFound.dateOfEvent}</p>
<img src="${qr}">
`;
let message = {
from: env.email,
to: email,
subject: `Ticket for ${eventFound.nameOfEvent}`,
html: mailTemplate,
};
transporter.sendMail(message, (error, info) => {
if (error) {
return res.status(500).json({ error: error });
} else console.log("Mail sent:", info.response);
});
return res.status(200).send(paymentIntent.client_secret);
} catch (error) {
next(error);
}
}
);
错误处理中间件:
app.use(function (err: any, req: any, res: any, next: any) {
console.error(err.message);
if (!err.statusCode) err.statusCode = 500;
res.status(err.statusCode).send(err.message);
});
自定义错误类:
class StatusError extends Error {
code: number;
constructor(message: string, code: number) {
super();
this.message = message;
this.code = code;
}
}
export default StatusError;
解决方案
问题是您对票证的检查是异步的,因此无论如何都会执行其余的功能。您需要等待结果才能决定要做什么。最简单的方法是将路由处理程序的其余部分嵌套在以下回调中Ticket.find
:
async (req: any, res: any, next: any) => {
try {
const errors = validationResult(req);
if (!errors.isEmpty()) {
let err = new StatusError("Error while validating body", 400);
next(err);
}
const { id, email, firstName, lastName, phoneNumber } = req.body;
let eventFound: any;
const event = await Event.findById(id, (error, result) => {
if (!error) eventFound = result;
else {
let err = new StatusError("No event found", 404);
next(err);
}
});
Ticket.find({ eventId: event?.id }, (error, tickets) => {
if (!error) {
if (event?.toJSON().maxTicketsAmount - 1 < tickets.length) {
let err = new StatusError("No tickets left", 403);
next(err);
return;
}
} else {
let err = new StatusError("No tickets found", 404);
next(err);
return;
}
const paymentIntent = await stripe.paymentIntents.create({
amount: eventFound.ticketPrice, // NEEDS TO BE ABOVE SOME VALUE!!!!!!!
currency: "pln",
payment_method_types: ["card"],
receipt_email: email,
metadata: { integration_check: "accept a payment" },
});
if (!paymentIntent) {
let err = new StatusError("Creating payment intent failed", 400);
next(err);
}
const ticket = new Ticket({
email: email.trim(),
firstName: firstName.trim(),
lastName: lastName.trim(),
phoneNumber: phoneNumber.trim(),
eventId: eventFound.id,
purchaseDate: new Date(),
});
ticket.save((error) => {
if (error) {
let err = new StatusError("Error while saving to DB", 500);
next(err);
}
});
const qr = await toDataURL(ticket.id);
console.log(ticket.id);
if (!qr) {
let err = new StatusError("Error while creating QR Code", 400);
next(err);
}
const mailTemplate = `
<h1>Hello ${firstName} ${lastName}</h1>
<p>Thanks for buying ticket for ${eventFound.nameOfEvent}, in ${eventFound.place}, taking place on ${eventFound.dateOfEvent}</p>
<img src="${qr}">
`;
let message = {
from: env.email,
to: email,
subject: `Ticket for ${eventFound.nameOfEvent}`,
html: mailTemplate,
};
transporter.sendMail(message, (error, info) => {
if (error) {
return res.status(500).json({ error: error });
} else console.log("Mail sent:", info.response);
});
return res.status(200).send(paymentIntent.client_secret);
});
} catch (error) {
next(error);
}
}
推荐阅读
- java - 替换Java中字符串的第一部分
- c# - 如何从另一个表中获取数据并插入到 EF Core 中所需的表中
- java - org.springframework.beans.factory.CannotLoadBeanClassException:找不到类 [com.spring.dao.StudentDao]
- oracle - 如何通过 Log Parser 查询建立到 Oracle 服务器的输出连接?
- python - 如何将图形的 x 轴标签更改为 10 的倍数?
- mql4 - 如何在 mql4 中绘制曲线进度图?
- visual-studio - 如何将 setup.vdproj 转换为 .NET5
- java - Spring boot - Jasper 子报表不可见
- ruby - 如何将数组转换为字符串数组?
- css - Sass @use 与 @import 包大小