Meteor:在服务器上正确使用Meteor.wrapAsync
Meteor: Proper use of Meteor.wrapAsync on server
背景
我正在尝试将条纹支付集成到我的网站中。我需要使用我的私有条纹密钥创建一个条纹用户。我将这个密钥存储在我的服务器上,并调用一个服务器方法来创建用户。也许还有其他方法可以做到这一点?下面是stripeapi(为了方便起见,复制到下面):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
});
我的尝试和结果
我一直在使用相同的客户端代码和不同的服务器代码。所有尝试都会立即在客户端控制台上给出未定义的.log(…),但在服务器控制台上给出正确的响应。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
}));
}
});
我也在没有Meteor.wrapAsync.的情况下尝试过这两种方法
编辑-我也在使用这个软件包:https://atmospherejs.com/mrgalaxy/stripe
来自Meteor.wrapAsync
http://docs.meteor.com/#meteor_wrapasync您可以看到,您需要向它传递一个函数和可选的上下文,而在您的两次尝试中,您将传递调用Stripe.customers.create
的异步版本的RESULT。
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);
}
});
Meteor.wrapAsync
将异步函数转换为一个方便的同步查找函数,该函数允许按顺序编写代码。(在后台,所有内容仍然在异步Node.js事件循环中执行)。
我们需要将API函数(Stripe.customers.create
)和函数上下文传递给Meteor.wrapAsync
,即API函数体中的this
,在本例中为Stripe.customers
。
编辑:
如何检索错误?
传统的节点式API函数通常将回调作为最后一个参数,该参数将在完成所需任务时最终被调用。这个回调有两个参数:error和data,根据调用结果,其中任何一个都将为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);
});
为什么Stripe不需要通过?
JavaScript没有"名称空间"的概念,因此API开发人员使用了定义一个全局对象作为API名称空间的常用技巧,该对象上定义的属性是API的"子模块"。这意味着Stripe.customers
是Stripe API的子模块,用于公开与客户相关的函数,因此这些函数的this
上下文是Stripe.customers
,而不是Stripe
。
您可以通过在浏览器控制台中复制粘贴以下嘲讽代码来自己测试:
Stripe={
customers:{
create:function(){
console.log(this==Stripe.customers);
}
}
};
然后在浏览器控制台中调用存根函数,如下所示:
> Stripe.customers.create();
true
另一个选项是这个包,它可以实现类似的目标。
meteor add meteorhacks:async
从包自述:
异步包装(函数)
包装一个异步函数,并允许它在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;
}
});
首先,感谢@saimeunt的回答,这让一些困难的概念变得清晰起来。然而,我遇到了一个问题,想要一个经典的异步回调(错误,结果)在客户端上显示错误和结果,这样我就可以在浏览器中提供信息。
我是这样解决的:
服务器代码:
var Stripe = StripeAPI(STRIPE_SECRET_KEY);
Meteor.methods({
createCust: Meteor.wrapAsync(Stripe.charges.create, Stripe.charges)
});
客户代码:
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);
});
看起来很整洁。然而不幸的是,wrapAsync有一个打开的错误(请参阅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');
});
由于您几乎需要将每个函数封装在Async中,因此您应该使用此包https://atmospherejs.com/copleykj/stripe-sync
,它使用WrapAsync预封装了所有条带函数,使您的生活更轻松,代码更干净。
- Meteor如何接收HTTP请求
- Meteor-将选定窗体中的对象添加到集合中
- Meteor上的启动页面
- MeteorJS:在带有回调的vzaar api上正确使用wrapAsync
- Meteor方法在客户端返回null,在客户端运行的相同方法返回正确的值
- Meteor-添加用户自定义字段的方法不起作用
- Meteor忘记了密码的实现
- 链接所有<a>Meteor
- Meteor wrapAsync正在使用
- Meteor - 使用 Meteor.wrapAsync() 包装 NPM
- 如何使Meteor方法在使用wrapAsync完成内部函数后返回结果
- 带Meteor.wrapAsync()的菊花链NPM包函数
- Meteor.WrapAsync don't return value
- Meteor:在服务器上正确使用Meteor.wrapAsync
- Meteor wrapAsync with Closures
- Meteor wrapAsync同步执行,但从不返回
- Meteor WrapAsync异步工作
- Meteor Wrapasync服务器端保存api调用结果到集合
- 流星.使用Meteor.Mandrill时,wrapAsync没有返回任何值
- 如何处理Meteor.wrapAsync上的错误