Meteor:在服务器上正确使用Meteor.wrapAsync

Ada*_*dam 50 javascript stripe-payments meteor

背景

我正在尝试将条带付款整合到我的网站中.我需要使用私有条带密钥创建条带用户.我将此密钥存储在我的服务器上,并调用服务器方法来创建用户.也许有另一种方法可以实现这一目标?这是条纹api(为方便起见,下面复制):https: //stripe.com/docs/api/node#create_customer

//stripe api call
var Stripe = StripeAPI('my_secret_key');

Stripe.customers.create({
  description: 'Customer for test@example.com',
  card: "foobar" // obtained with Stripe.js
}, function(err, customer) {
  // asynchronously called
});
Run Code Online (Sandbox Code Playgroud)

我的尝试和结果

我一直在使用不同服务器代码的相同客户端代码.所有尝试都会在客户端的console.log(...)上立即给出undefined,但在服务器console.log(...)上给出正确的响应:

//client
Meteor.call('stripeCreateUser', options, function(err, result) {
  console.log(err, result);
});

//server attempt 1
var Stripe = StripeAPI('my_secret_key');

Meteor.methods({
    stripeCreateUser: function(options) {  
        return Meteor.wrapAsync(Stripe.customers.create({
            description: 'Woot! A new customer!',
            card: options.ccToken,
            plan: options.pricingPlan
        }, function (err, res) {
            console.log(res, err);
            return (res || err);
        }));
    }
});

//server attempt 2
var Stripe = StripeAPI('my_secret_key');

Meteor.methods({
    stripeCreateUser: function(options) {  
        return Meteor.wrapAsync(Stripe.customers.create({
            description: 'Woot! A new customer!',
            card: options.ccToken,
            plan: options.pricingPlan
        }));
    }
});
Run Code Online (Sandbox Code Playgroud)

我也试过没有Meteor.wrapAsync.

编辑 - 我也在使用这个软件包:https: //atmospherejs.com/mrgalaxy/stripe

sai*_*unt 74

Meteor.wrapAsync http://docs.meteor.com/#meteor_wrapasync中可以看到,您需要向它传递一个函数和可选的上下文,而在您的两次尝试中,您将传递调用异步版本的结果Stripe.customers.create.

Meteor.methods({
  stripeCreateUser: function(options) {
    // get a sync version of our API async func
    var stripeCustomersCreateSync=Meteor.wrapAsync(Stripe.customers.create,Stripe.customers);
    // call the sync version of our API func with the parameters from the method call
    var result=stripeCustomersCreateSync({
      description: 'Woot! A new customer!',
      card: options.ccToken,
      plan: options.pricingPlan
    });
    // do whatever you want with the result
    console.log(result);
  }
});
Run Code Online (Sandbox Code Playgroud)

Meteor.wrapAsync将异步函数转换为方便的同步函数,允许编写顺序查找代码.(发动机故障仍然在异步Node.js事件循环中执行).

我们需要传递Meteor.wrapAsync我们的API函数(Stripe.customers.create)以及函数上下文,即this在API函数的主体内部,在本例中是Stripe.customers.

编辑:

如何检索错误?

传统节点样式API函数通常将回调作为最后一个参数,最终将在所需任务完成时调用.此回调有两个参数:错误和数据,根据调用结果,其中一个将为null.

我们如何使用由Meteor.wrapAsync?返回的同步包装函数来访问错误对象?

我们必须依赖于使用try/catch块,因为如果出现错误,它将被sync函数抛出,而不是作为异步函数回调的第一个参数传递.

try{
  var result=syncFunction(params);
  console.log("result :",result);
}
catch(error){
  console.log("error",error);
}
// is the equivalent of :
asyncFunc(params,function(error,result){
  if(error){
    console.log("error",error);
    return;
  }
  console.log("result :",result);
});
Run Code Online (Sandbox Code Playgroud)

为什么Stripe不需要传递?

JavaScript没有"命名空间"概念,因此API开发人员使用定义充当API命名空间的全局对象的常用技巧,在此对象上定义的属性是API的"子模块".这意味着它Stripe.customers是Stripe API的一个子模块,它暴露了与客户相关的函数,因此这些函数的this上下文Stripe.customers不是Stripe.

您可以通过在浏览器控制台中复制粘贴此模拟代码来自行测试:

Stripe={
  customers:{
    create:function(){
      console.log(this==Stripe.customers);
    }
  }
};
Run Code Online (Sandbox Code Playgroud)

然后在浏览器控制台中调用存根函数,如下所示:

> Stripe.customers.create();
true
Run Code Online (Sandbox Code Playgroud)


Ful*_*ack 11

另一个选择是这个实现了类似的目标.

meteor add meteorhacks:async
Run Code Online (Sandbox Code Playgroud)

从包README:

Async.wrap(功能)

包装异步函数并允许它在没有回调的情况下在Meteor中运行.

//declare a simple async function
function delayedMessge(delay, message, callback) {
  setTimeout(function() {
    callback(null, message);
  }, delay);
}

//wrapping
var wrappedDelayedMessage = Async.wrap(delayedMessge);

//usage
Meteor.methods({
  'delayedEcho': function(message) {
    var response = wrappedDelayedMessage(500, message);
    return response;
  }
});
Run Code Online (Sandbox Code Playgroud)

  • 是的,你可以这样做.请注意,Meteor回调是异步的.请参见http://docs.meteor.com/#/full/meteor_call (2认同)

mwa*_*ren 7

首先,感谢@saimeunt的回答,这使得一些困难的概念变得清晰.但是我遇到了一个问题,即想要一个经典的异步回调(错误,结果),在客户端上显示错误和结果,以便我可以在浏览器中提供信息性消息.

我这样解决了:

服务器代码:

var Stripe = StripeAPI(STRIPE_SECRET_KEY);

Meteor.methods({
    createCust: Meteor.wrapAsync(Stripe.charges.create, Stripe.charges)
});
Run Code Online (Sandbox Code Playgroud)

客户代码:

var stripeCallOptions = {
    description: 'Woot! A new customer!',
    card: ccToken,
    plan: pricingPlan
};


Meteor.call('createCust', stripeCallOptions, function(error, result){
    console.log('client error', error);
    console.log('client result', result);
});
Run Code Online (Sandbox Code Playgroud)

看起来整洁.但是不幸的是,wrapAsync有一个开放的bug,(参见https://github.com/meteor/meteor/issues/2774)因为它没有为调用者恢复正确的错误.一个名为Faceyspacey的天才编写了一个名为Meteor.makeAsync()的替代品,您可以在我提到的错误页面上找到它,但是它会将结果或错误返回给'result'变量,使'error'变量保持未定义状态.我现在很好,至少我对正确的错误对象有一个钩子.

如果你使用makeAsync(),你需要像这样导入Futures:

Meteor.startup(function () {
    //this is so that our makeAsync function works
    Future = Npm.require('fibers/future');
});
Run Code Online (Sandbox Code Playgroud)