Javascript 使用Node.js时,条带API调用正在生成多个订阅

Javascript 使用Node.js时,条带API调用正在生成多个订阅,javascript,node.js,api,asynchronous,stripe-payments,Javascript,Node.js,Api,Asynchronous,Stripe Payments,我正在我的节点应用程序中实现条带api。我遇到的问题是,如果我多次快速单击submit按钮,就会多次调用api,stripe客户会突然有多个订阅和费用 这种情况下,用户拥有一个没有订阅的条带客户帐户,因为他们以前已取消订阅。现在,由于旧计划已被删除,他们希望重新订阅新计划 我的代码逻辑如下: 1. Submit form 2. I retrieve the user from my mongo db 3. I retrieve the customer from stripe using a s

我正在我的节点应用程序中实现条带api。我遇到的问题是,如果我多次快速单击submit按钮,就会多次调用api,stripe客户会突然有多个订阅和费用

这种情况下,用户拥有一个没有订阅的条带客户帐户,因为他们以前已取消订阅。现在,由于旧计划已被删除,他们希望重新订阅新计划

我的代码逻辑如下:

1. Submit form
2. I retrieve the user from my mongo db
3. I retrieve the customer from stripe using a stored customer id (api call)
4. I create a customer subscription (api call)
5. I update the stripe customer object with their credit card (api call)
6. Respond back to user
  • 以上所有操作都是使用异步瀑布来完成的,每个后续的异步调用都在一个单独的函数中
我想要什么:

  • 在第3步和第4步之间,我希望检索客户并检查他或她是否已经订阅,如果用户已经有活动订阅,则防止发生第4步和第5步
问题:

  • 我正在测试这样一个场景:用户多次单击submit按钮,最终要为几个订阅付费。我认为这与node如何一次发送多个请求有关,因为它是异步的,我想检查是否进行了api调用,以检查是否设置了太长的时间,并且node在发送所有请求时没有等待
我该如何着手解决这个问题

注意:当然,我有前端来处理这个问题,以防止用户多次提交表单,但这并不理想,也不希望这成为我唯一的防线


感谢使用功能强大的速率限制器库


这将限制每个会话(每个用户浏览器)

使用功能强大的速率限制器库


这将限制每个会话(每个用户浏览器)

一种方法是保留最近交易的缓存(在Redis或类似工具中),通过从关键交易值(例如客户id、日期、时间、金额)派生的散列进行索引


将订阅请求提交到stripe之前,请将当前事务与缓存进行比较。如果点击,您可以显示错误、自动忽略交易或让用户选择是否继续。

一种方法是保留最近交易的缓存(在Redis或类似工具中),通过从关键交易值(例如客户id、日期、时间、金额)派生的哈希索引


将订阅请求提交到stripe之前,请将当前事务与缓存进行比较。如果点击,您可以显示错误,自动忽略事务,或者让用户选择是否继续。

在第一次单击时立即使用javascript禁用前端中的按钮。

在第一次单击时立即使用javascript禁用前端中的按钮。

Stripe具有内置功能,可帮助您防止出现这种情况

您需要生成一个唯一的字符串,并将其与条带请求一起发送


将它以隐藏的形式放入HTML中,即CORS令牌,然后读取它并将其放入条带调用中,可以防止双击/重试。

条带内置了帮助您防止这种情况的功能

您需要生成一个唯一的字符串,并将其与条带请求一起发送


将它以隐藏的形式放入HTML中,一个la your CORS令牌,然后读取它并将其放入Stripe调用将防止双击/重试。

我尝试了一下,它似乎可以阻止每个用户,而不仅仅是那个用户。我的应用程序是无状态的,因此没有任何会话。我使用JSON Web令牌进行身份验证以防止会话的需要。啊,我很抱歉。每个用户的限制器将类似于密钥为req.connection.remoteAddress的情况。我尝试了一下,它似乎可以阻止每个用户,而不仅仅是那个用户。我的应用程序是无状态的,因此没有任何会话。我使用JSON Web令牌进行身份验证以防止会话的需要。啊,我很抱歉。每用户限制器类似于密钥为req.connection.remoteAddress的情况
var RateLimiter = require('limiter').RateLimiter;

// Allow 1 requests per minute
var limiterPayments = new RateLimiter(1, 'minute');

exports.payWithStripe = function(req,res){
    limiterPayments.removeTokens(1,function(err,remainingRequests){
    if (err){
        return res.sendStatus(429);
    } else {
        // continue with stripe payment
    }
}