![](/img/trans.png)
[英]Multiple request url mapping handler in one controller does not work in Node Express JS
[英]Node js: How to handler multiple request in one API
假设这是我的 API:
app.post('/refund', function (req, res) {
Transaction.findOneAndUpdate({_id: req.body.transaction_id}, {$set: {refund_status: true}}).
exec(function (err, transaction_status) {
res.end("Refund successfully")
}
}
如果两个管理员同时点击退款按钮。 我的客户将收到双倍退款。
那么,如何预防这些问题呢?
只需先获取交易并检查退款状态并更新即可。 如果是虚假退款。 如果它是真的告诉它已经退款了。
app.post('/refund', function (req, res) {
// get the transaction first
Transaction.find({_id: req.body.transaction_id}, function(err, doc) {
if (doc.refund_status == false) {
Transaction.findOneAndUpdate({_id: req.body.transaction_id}, {$set: {refund_status: true}}).exec(function(err, transaction_status) {
res.end("Refund successfully")
})
} else { // already refunded
res.end("Already refunded")
}
})
}
首先,您应该在第一次完成之前禁用两次单击退款按钮的可用性(以获得更好的用户体验)。
为了防止这种情况在后端发生,您可以使用 rate limit the specific route 。
如果您使用的是 express,您应该查看express-slow-down或express-rate-limit
一个可能的解决方案是:
const slowDown = require("express-slow-down");
/* app.enable("trust proxy"); only if you're behind a reverse proxy (Heroku,
Bluemix, AWS if you use an ELB, custom Nginx setup, etc) */
const refundSpeedLimiter = slowDown({
windowMs: 10 * 1000, // 10 seconds
delayAfter: 1, // allow the first request to go at full-speed, then...
delayMs: 1.5 * 1000 // 2nd request has a **1.5s** delay, 3rd has a **3s** delay, 4th gets 4.5s, etc.
});
app.post('/refund', refundSpeedLimiter, function (req, res) {
// Fetch The Transaction
Transaction.find({_id: req.body.transaction_id}, function(err, doc) {
// Check if its not already refunded.
if (doc.refund_status == false) {
Transaction.findOneAndUpdate({_id: req.body.transaction_id}, {$set: {refund_status: true}}).exec(function(err, transaction_status) {
res.end("Refund successfully")
})
} else { // already refunded
res.end("Already refunded")
}
})
}
如express-rate-limit
中所述:
默认情况下,此模块不与其他进程/服务器共享状态。 如果您需要更强大的解决方案,我建议使用外部存储。 有关外部商店的列表,请参阅下面的商店部分。
请注意,默认存储是Memory store ,因此默认情况下它允许多个实例。 如果您打算使用不同的存储(它允许跨多个节点实例使用速率限制 - 就像在集群模式中),您将需要为每个ratelimit
实例设置一个自定义键。
在session.withTransaction()的回调中实现您的退款逻辑。 这将防止并发更新。 不要担心异步的东西; .withTransaction() 正确处理它。
或者,使您的退款逻辑具有幂等性。 也就是说,以多次调用它与调用一次完全相同的方式实现它。 您的设置几乎是幂等的:您从交易 id 开始并将其退款状态设置为 true。 但是,如果您必须在交易已经退款时进行报告,则幂等性可能对您不起作用。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.