与Stripe API一起使用时,Meteor.wrapasync不能正确返回错误

时间:2014-11-10 16:07:55

标签: meteor stripe-payments

我正在将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。 谢谢你的帮助

2 个答案:

答案 0 :(得分:2)

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

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

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

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

其次,使用API​​。我发现放入包含大量注释的代码块更容易。错误返回的主要问题是您无法访问顶级错误对象,因为返回的格式是唯一的。因此,访问对象中的项目。看看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进行交互。您将成功或错误返回给客户端。

所以它总体上看起来像......

  • 用户提交某种表单。条带客户端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;

    },
  }
});
祝你好运。

答案 1 :(得分:1)

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