Meteor:在服务器上正确使用 Meteor.wrapAsync [英] Meteor: Proper use of Meteor.wrapAsync on server

查看:24
本文介绍了Meteor:在服务器上正确使用 Meteor.wrapAsync的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

背景

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

//stripe api调用var Stripe = StripeAPI('my_secret_key');Stripe.customers.create({描述:'test@example.com 的客户',card: "foobar"//用 Stripe.js 获得},功能(错误,客户){//异步调用});

我的尝试和结果

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

//客户端Meteor.call('stripeCreateUser', options, function(err, result) {控制台日志(错误,结果);});//服务器尝试1var Stripe = StripeAPI('my_secret_key');流星.方法({条纹创建用户:函数(选项){return Meteor.wrapAsync(Stripe.customers.create({描述:'哇!新客户!',卡:options.ccToken,计划:options.pricingPlan},函数(错误,res){控制台日志(资源,错误);返回(res || 错误);}));}});//服务器尝试2var Stripe = StripeAPI('my_secret_key');流星.方法({条纹创建用户:函数(选项){return Meteor.wrapAsync(Stripe.customers.create({描述:'哇!新客户!',卡:options.ccToken,计划:options.pricingPlan}));}});

我也试过没有 Meteor.wrapAsync.

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

解决方案

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

Meteor.methods({条纹创建用户:函数(选项){//获取我们 API async func 的同步版本var stripeCustomersCreateSync=Meteor.wrapAsync(Stripe.customers.create,Stripe.customers);//使用方法调用中的参数调用我们 API func 的同步版本var 结果=stripeCustomersCreateSync({描述:'哇!新客户!',卡:options.ccToken,计划:options.pricingPlan});//对结果做任何你想做的事控制台日志(结果);}});

Meteor.wrapAsync 将异步函数转换为方便的同步查找函数,允许编写顺序查找的代码.(在后台,所有内容仍然在异步 Node.js 事件循环中执行).

我们需要将我们的 API 函数 (Stripe.customers.create) 连同函数上下文一起传递给 Meteor.wrapAsync,即 this在 API func 的主体内,在本例中为 Stripe.customers.

<块引用>

如何检索错误?

传统的节点样式 API 函数通常将回调作为最后一个参数,当所需的任务完成时,最终会调用该回调.这个回调函数有 2 个参数:error 和 data,根据调用的结果,其中一个为 null.

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

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

尝试{var 结果=syncFunction(params);console.log("结果:",result);}捕捉(错误){控制台日志(错误",错误);}//相当于:asyncFunc(params,function(error,result){如果(错误){控制台日志(错误",错误);返回;}console.log("结果:",result);});

<块引用>

为什么不需要通过 Stripe?

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

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

条纹={顾客:{创建:功能(){console.log(this==Stripe.customers);}}};

然后像这样在浏览器控制台中调用存根函数:

>Stripe.customers.create();真的

Background

I'm trying to integrate stripe payments into my site. I need to create a stripe user using my private stripe key. I'm storing this key on my server, and calling a server method to create the user. Maybe there's another way of accomplishing this? Here's the stripe api (copied below for convenience): 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
});

My attempts and results

I've been using the same client code with different server code. All attempts immediately give undefined on the client's console.log(...) but give the proper response on the server 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
        }));
    }
});

I've also tried both without Meteor.wrapAsync.

EDIT - I'm also using this package: https://atmospherejs.com/mrgalaxy/stripe

解决方案

From the Meteor.wrapAsync http://docs.meteor.com/#meteor_wrapasync you can see that you need to pass it a function and optionally a context, whereas on your two attempts you are passing the RESULT of calling the async version of 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);
  }
});

Meteor.wrapAsync transforms an async function into a convenient synchronous-looking function which allows to write sequentially looking code. (underhood everything is still executed within the asynchronous Node.js event loop).

We need to pass to Meteor.wrapAsync our API function (Stripe.customers.create) along with the function context, ie this inside the body of the API func, which in this case is Stripe.customers.

EDIT :

How to retrieve errors ?

Traditional node style API functions usually take a callback as last argument that will get called ultimately when the required task is completed. This callback takes 2 arguments : error and data, either one will be null according to the result of the call.

How do we access the error object using the synchronous wrapped functions returned by Meteor.wrapAsync ?

We have to rely on using try/catch blocks, because in case of error, it will be thrown by the sync function instead of being passed as first argument of the async function callback.

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);
});

why doesn't Stripe need to be passed?

JavaScript has no "namespace" concept, so API developers use the common trick of defining a global object acting as API namespace, properties defined on this object are "sub-modules" of the API. It means that Stripe.customers is a submodule of the Stripe API exposing customers-related funcs, and as such these funcs this context is Stripe.customers, not Stripe.

You can test it yourself by copy pasting this mocking code in your browser console :

Stripe={
  customers:{
    create:function(){
      console.log(this==Stripe.customers);
    }
  }
};

And then calling the stub function in your browser console like this :

> Stripe.customers.create();
true

这篇关于Meteor:在服务器上正确使用 Meteor.wrapAsync的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆