【问题标题】:Meteor.wrapasync when used with Stripe API won't return error properlyMeteor.wrapasync 与 Stripe API 一起使用时不会正确返回错误
【发布时间】:2015-01-07 00:01:06
【问题描述】:

我正在将 Stripe API 集成到我的应用中。我在服务器上使用如下方法

stripeRegister: function(token) {    
    // Create the secret key on the server
    var Stripe = StripeAPI(Meteor.settings.Stripe.secretKey);
    var syncFunction = Meteor.wrapAsync(Stripe.charges.create, Stripe.charges);

    var stripeToken = token.stripeToken;

    try {
      console.log("try")

      var charge = syncFunction({
        amount: 1000,
        currency: "usd",
        card: stripeToken,
        description: "payinguser@example.com"
      });

      console.log(charge);
      console.log("after charge")

      return charge;
    }
    catch(e) {
      console.log("error")
      console.log(charge);
      console.log(e);
      throw new Meteor.Error(402, e);
    }
}

现在这可以很好地收取费用。如果你给它一张好的信用卡,它会很高兴。但是,如果你给它一个不是的,并且由于多种原因而出现错误,你可能会得到一个错误,它会给你一个Exception while invoking method 'stripeRegister' undefined 错误。

如果您尝试在 syncFunction 调用中给它回调,它将打印您的错误,但是您不再以正确的方式做事,并且无法正确抛出错误,因为您不是“同步“不再。例如,

var charge = syncFunction({
  amount: 1000,
  currency: "usd",
  card: stripeToken,
  description: "payinguser@example.com"
  }, function(err, charge) {
  if (err && err.type === 'StripeCardError') {
    // The card has been declined
  }
});

我假设我传入了正确的 this 上下文(它返回良好的事实让我认为这是正确的),但为什么此时会有 undefined 调用?它不应该调用Stripe.charges.create 函数的回调并将其放入catch 块中吗?

我在创建解决方案时经常引用这个问题Meteor.WrapAsync don't return value。 感谢您的帮助

【问题讨论】:

    标签: meteor stripe-payments


    【解决方案1】:

    所以找到了一个临时修复。我说是暂时的,因为它不像我想要的那样优雅。无论如何,我通过以下方式解决了错误问题。希望这对以后的其他人有所帮助(并为您节省大量时间)。

    首先,确保将以下包添加到您的项目中

    copleykj:stripe-sync
    grove:stripe-checkout
    grove:stripe-npm
    grove:stripe.js
    

    还有其他适用于此的软件包,但这些恰好是我选择的。 copleykj:stripe-sync 包非常棒,因为它使整个条带包异步,这为您节省了大量使用它的时间。

    其次,使用 API。我发现只放入一个包含大量 cmets 的代码块更容易。错误返回的主要问题是您无法访问顶级错误对象,因为返回的格式是唯一的。因此,请访问对象内的项目。查看 switch 语句以了解我的意思。以下方法仅在服务器上。

    有关所有封装方法的完整列表,请查看stripe sync package page

    // 使用你要支付的账户的访问令牌 // 如果您直接接受自己的付款,这是您的 API 令牌 // 如果您代表某人接受付款,则其令牌是从 Stipe Connect 路径获得的

    var Stripe = StripeSync(access_token);
    
    try{
      // Just to show you its working
      var account = Stripe.account.retrieve()
      console.log(account);
    
      // An example charge
      // includes a application fee and the access token of the account you are charging
      var charge = Stripe.charges.create({
        amount: 1299,
        currency: "usd",
        card: 'some_card_token',
        description: "Test charge",
        application_fee: 299
      },
      access_token);
    
      console.log(charge);
    
    }catch(error){
      // You can't do console.log(error) because it throws a server error
      // you can access the error.type and error.message though
      console.log(error.type);
      console.log(error.message);
    
      // Customize the return 
      switch (error.type) {
        case 'StripeCardError':
          // A declined card error
          // error.message; // => e.g. "Your card's expiration year is invalid."
          throw new Meteor.Error(1001, error.message);
          break;
        case 'StripeInvalidRequest':
          // Invalid parameters were supplied to Stripe's API
          throw new Meteor.Error(1001, error.message);
          break;
        case 'StripeAPIError':
          // An error occurred internally with Stripe's API
          throw new Meteor.Error(1001, error.message);
          break;
        case 'StripeConnectionError':
          // Some kind of error occurred during the HTTPS communication
          throw new Meteor.Error(1001, error.message);
          break;
        case 'StripeAuthenticationError':
          // You probably used an incorrect API key
          throw new Meteor.Error(1001, error.message);
          break;
        default:
          throw new Meteor.Error(1001, error.message);
      }
    }
    

    第三,整个图案。

    在客户端:您有提交的表单。您可以使用自定义表单实现或 Stripe Checkout 之一。我使用 Stripe Checkout 是因为它看起来更漂亮,而且他们为我做了很多验证(懒惰!)。从这里您使用Meteor.call 将调用发送到服务器并等待响应。

    在服务器上:您使用我上面展示的方法在服务器上与 API 进行交互。您向客户端返回成功或错误。

    所以总体上看起来是这样的......

    • 用户提交了一些表单。 Stripe 客户端 API 为您提供了一个令牌。
    • 您使用Meteor.call 调用服务器并将令牌与任何其他相关信息一起传递。
    • 在服务器上,您使用StripeSync 包和try/catch 块与API 交互。
    • 根据 API 的响应,返回成功或错误。
    • 在客户端的错误处理函数中,显示成功或失败。

    客户端代码示例,以防您想知道。复制粘贴不起作用,因为它对我来说有点特定的代码,但你可以从中得到一般的想法。我正在使用StripeCheckout,所以如果您使用自定义表单,您所做的几乎所有事情都将在onSubmit 函数中。您将在rendered 函数中进行基本配置。作为结帐回调的一部分,我必须做更多的事情。另外,我使用Autoform 来处理表单。

    Template.someTemplate.rendered = function() {
    
      // Need to interval the initialize to make sure its executing faster than it should
      var newInterval = Meteor.setInterval(function() {
        if (StripeCheckout) {
          Meteor.clearInterval(newInterval);
          var stripePubKey = stripe_publishable_key;
    
          handler = StripeCheckout.configure({
            key: stripePubKey,
            image: 'logo-compact-black@2x.png',
            token: function(token) {
              // Use the token to create the charge with a server-side script.
              // You can access the token ID with `token.id`
    
              var thisForm = AutoForm.getFormValues('registerForEventForm');
    
              Meteor.call('someServerCall', thisForm.insertDoc, thisForm.updateDoc, currentDoc, token, function(error, id) {
                console.log("\nMeteor call has returned");
                if (error) {
                  // display error to the user
                  throwError(error.reason);
                  $("#btn").prop('disabled', false);
                }else{
                  throwNotification("Successful registration and card payment.", "success");
                }
              });
            }
          });
    
          // Allow the button to be used to submit form
          $("#btn").prop('disabled', false);
        }
      }, 50);
    };
    
    
    
    AutoForm.hooks({
      registerForEventForm: {
        // Called when form does not have a `type` attribute
        onSubmit: function(insertDoc, updateDoc, currentDoc) {
    
          // Open Checkout with further options
          handler.open({
            name: 'Some App',
            description: 'Registration Cost for '+currentDoc.title,
            amount: 1299,
            email: Meteor.user().emails[0].address,
            closed: function() {
              $("#btn").prop('disabled', false);
            }
          });
    
          return false;
    
        },
      }
    });
    

    祝你好运。

    【讨论】:

    • 你可以用我在底部推荐的解决方案更轻松地解决这个问题:虽然你无法获得完整的原始错误对象。我的解决方案贴在这里:github.com/meteor/meteor/issues/2774 ...只需将方法更改为 Meteor.makeAsync 并使用它,而无需添加一堆同步特定条带库
    【解决方案2】:

    我认为这是目前的一个错误。见这里:https://github.com/meteor/meteor/issues/2774

    【讨论】:

    • 谢谢本。看起来是这样的。
    猜你喜欢
    • 2018-11-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-06
    • 2011-08-27
    • 1970-01-01
    • 2023-02-04
    • 1970-01-01
    相关资源
    最近更新 更多