Wrapping Stripe 在 Meteor 的 Fibers 中创建客户回调
Wrapping Stripe create customer callbacks in Fibers in Meteor
我在创建新客户时无法让 Stripe.js 工作。这是他们教程中的 Node.js 代码:
// Set your secret key: remember to change this to your live secret key in production
// See your keys here https://dashboard.stripe.com/account/apikeys
var stripe = require("stripe")("sk_test_9999999999999999999999");
// (Assuming you're using express - expressjs.com)
// Get the credit card details submitted by the form
var stripeToken = request.body.stripeToken;
stripe.customers.create({
source: stripeToken,
description: 'payinguser@example.com'
}).then(function(customer) {
return stripe.charges.create({
amount: 1000, // amount in cents, again
currency: "usd",
customer: customer.id
});
}).then(function(charge) {
saveStripeCustomerId(user, charge.customer);
});
这是我的尝试。我将所有回调包装在 Meteor.bindEnvironment
中,因为异步回调需要 运行 在纤程中。我在服务器控制台中收到错误消息:
Exception while invoking method 'submitOrder' Error: Stripe: Unknown arguments (function (/* arguments */) {
谁能指出我用纤维包裹它的正确方向?或者利用 Meteor.wrapAsync?
var createStripeCustomer = function(ShoppingCartObject){
check(ShoppingCartObject, Object);
var stripe = Stripe("sk_test_9999999999999999");
// (Assuming you're using express - expressjs.com)
// Get the credit card details submitted by the form
var stripeToken = ShoppingCartObject.charge.token;
stripe.customers.create(
{
source: stripeToken,
description: ShoppingCartObject._id,
email: ShoppingCartObject.customerInfo.agentEmail,
},
Meteor.bindEnvironment(function(customer){
return stripe.charges.create({
amount: ShoppingCartObject.totalPrice, // amount in cents, again
currency: "usd",
customer: customer.id
});
}),
Meteor.bindEnvironment(function(charge){
ShoppingCartObject.charge.customer = charge.customer;
submitOrder(ShoppingCartObject);
})
);
};
var submitOrder = function(ShoppingCartObject){
check(ShoppingCartObject, Object);
var data = _.omit(ShoppingCartObject, '_id');
var setHash = { $set: data };
ShoppingCarts.update({_id: ShoppingCartObject._id}, setHash);
};
这是对我有用的方法的简化版本。我基本上为 returns 一个 Future.
的每个 Stripe 调用创建了一个函数
// Server
var Future = Npm.require('fibers/future');
function createCustomer(token){
var future = new Future;
Stripe.customers.create({
card: token.id,
email: token.email
}, function(error, result){
if (error){
future.return(error);
} else {
future.return(result);
}
});
return future.wait();
}
Meteor.methods({
purchase: function(token){
check(token: Object);
try {
var customer = createCustomer(token);
} catch(error) {
// error handle
}
// create charge, etc. repeating same pattern
}
});
我决定使用 Meteor.wrapAsync()
来解决所有问题。以下代码:
编辑
考虑到这一点后,wrapAsync()
似乎有一些严重的错误处理限制,尤其是对于 Stripe,错误会很常见,我下面的实现可能不太理想。
相关讨论在这里:https://github.com/meteor/meteor/issues/2774
用户 faceyspacey
有这段代码可以创建一个 "better" wrapAsync
来更直观地处理错误,尽管我还没有尝试过。
Meteor.makeAsync = function(fn, context) {
return function (/* arguments */) {
var self = context || this;
var newArgs = _.toArray(arguments);
var callback;
for (var i = newArgs.length - 1; i >= 0; --i) {
var arg = newArgs[i];
var type = typeof arg;
if (type !== "undefined") {
if (type === "function") {
callback = arg;
}
break;
}
}
if(!callback) {
var fut = new Future();
callback = function(error, data) {
fut.return({error: error, data: data});
};
++i;
}
newArgs[i] = Meteor.bindEnvironment(callback);
var result = fn.apply(self, newArgs);
return fut ? fut.wait() : result;
};
};
原代码如下
ShoppingCartObject
包含订单的详细信息以及 Stripe.js
在您将其提供给客户的信用卡详细信息时生成的 cardToken
。
创建了一个新客户并保存了 cardToken
,实质上是保存了他们的 CC 信息供以后使用。
最后,使用他们的 CC 向客户收取费用。
下面的代码
var createStripeCustomerAsync = function(ShoppingCartObject, callback){
var stripe = Stripe("sk_test_999999999999999999");
stripe.customers.create({
// this is the token generated on the client side from the CC info
source: ShoppingCartObject.charge.cardToken,
email: ShoppingCartObject.customer.email
}, function(err, customer) {
callback(err, customer);
});
};
var createStripeCustomerSync = Meteor.wrapAsync(createStripeCustomerAsync);
var createStripeChargeAsync = function(customer, ShoppingCartObject, callback){
var stripe = Stripe("sk_test_999999999999999999");
stripe.charges.create({
amount: ShoppingCartObject.totalPrice, // amount in cents, again
currency: "usd",
customer: customer.id
}, function(error, charge){
callback(error, charge);
});
};
var createStripeChargeSync = Meteor.wrapAsync(createStripeChargeAsync);
var submitOrder = function(ShoppingCartObject){
check(ShoppingCartObject, Object);
var customer = createStripeCustomerSync(ShoppingCartObject);
console.log("customer: ", customer);
var charge = createStripeChargeSync(customer, ShoppingCartObject);
console.log("charge: ", charge);
var data = _.omit(ShoppingCartObject, '_id');
var setHash = { $set: data };
ShoppingCarts.update({_id: ShoppingCartObject._id}, setHash);
};
我在创建新客户时无法让 Stripe.js 工作。这是他们教程中的 Node.js 代码:
// Set your secret key: remember to change this to your live secret key in production
// See your keys here https://dashboard.stripe.com/account/apikeys
var stripe = require("stripe")("sk_test_9999999999999999999999");
// (Assuming you're using express - expressjs.com)
// Get the credit card details submitted by the form
var stripeToken = request.body.stripeToken;
stripe.customers.create({
source: stripeToken,
description: 'payinguser@example.com'
}).then(function(customer) {
return stripe.charges.create({
amount: 1000, // amount in cents, again
currency: "usd",
customer: customer.id
});
}).then(function(charge) {
saveStripeCustomerId(user, charge.customer);
});
这是我的尝试。我将所有回调包装在 Meteor.bindEnvironment
中,因为异步回调需要 运行 在纤程中。我在服务器控制台中收到错误消息:
Exception while invoking method 'submitOrder' Error: Stripe: Unknown arguments (function (/* arguments */) {
谁能指出我用纤维包裹它的正确方向?或者利用 Meteor.wrapAsync?
var createStripeCustomer = function(ShoppingCartObject){
check(ShoppingCartObject, Object);
var stripe = Stripe("sk_test_9999999999999999");
// (Assuming you're using express - expressjs.com)
// Get the credit card details submitted by the form
var stripeToken = ShoppingCartObject.charge.token;
stripe.customers.create(
{
source: stripeToken,
description: ShoppingCartObject._id,
email: ShoppingCartObject.customerInfo.agentEmail,
},
Meteor.bindEnvironment(function(customer){
return stripe.charges.create({
amount: ShoppingCartObject.totalPrice, // amount in cents, again
currency: "usd",
customer: customer.id
});
}),
Meteor.bindEnvironment(function(charge){
ShoppingCartObject.charge.customer = charge.customer;
submitOrder(ShoppingCartObject);
})
);
};
var submitOrder = function(ShoppingCartObject){
check(ShoppingCartObject, Object);
var data = _.omit(ShoppingCartObject, '_id');
var setHash = { $set: data };
ShoppingCarts.update({_id: ShoppingCartObject._id}, setHash);
};
这是对我有用的方法的简化版本。我基本上为 returns 一个 Future.
的每个 Stripe 调用创建了一个函数// Server
var Future = Npm.require('fibers/future');
function createCustomer(token){
var future = new Future;
Stripe.customers.create({
card: token.id,
email: token.email
}, function(error, result){
if (error){
future.return(error);
} else {
future.return(result);
}
});
return future.wait();
}
Meteor.methods({
purchase: function(token){
check(token: Object);
try {
var customer = createCustomer(token);
} catch(error) {
// error handle
}
// create charge, etc. repeating same pattern
}
});
我决定使用 Meteor.wrapAsync()
来解决所有问题。以下代码:
编辑
考虑到这一点后,wrapAsync()
似乎有一些严重的错误处理限制,尤其是对于 Stripe,错误会很常见,我下面的实现可能不太理想。
相关讨论在这里:https://github.com/meteor/meteor/issues/2774
用户 faceyspacey
有这段代码可以创建一个 "better" wrapAsync
来更直观地处理错误,尽管我还没有尝试过。
Meteor.makeAsync = function(fn, context) {
return function (/* arguments */) {
var self = context || this;
var newArgs = _.toArray(arguments);
var callback;
for (var i = newArgs.length - 1; i >= 0; --i) {
var arg = newArgs[i];
var type = typeof arg;
if (type !== "undefined") {
if (type === "function") {
callback = arg;
}
break;
}
}
if(!callback) {
var fut = new Future();
callback = function(error, data) {
fut.return({error: error, data: data});
};
++i;
}
newArgs[i] = Meteor.bindEnvironment(callback);
var result = fn.apply(self, newArgs);
return fut ? fut.wait() : result;
};
};
原代码如下
ShoppingCartObject
包含订单的详细信息以及Stripe.js
在您将其提供给客户的信用卡详细信息时生成的cardToken
。创建了一个新客户并保存了
cardToken
,实质上是保存了他们的 CC 信息供以后使用。最后,使用他们的 CC 向客户收取费用。
下面的代码
var createStripeCustomerAsync = function(ShoppingCartObject, callback){
var stripe = Stripe("sk_test_999999999999999999");
stripe.customers.create({
// this is the token generated on the client side from the CC info
source: ShoppingCartObject.charge.cardToken,
email: ShoppingCartObject.customer.email
}, function(err, customer) {
callback(err, customer);
});
};
var createStripeCustomerSync = Meteor.wrapAsync(createStripeCustomerAsync);
var createStripeChargeAsync = function(customer, ShoppingCartObject, callback){
var stripe = Stripe("sk_test_999999999999999999");
stripe.charges.create({
amount: ShoppingCartObject.totalPrice, // amount in cents, again
currency: "usd",
customer: customer.id
}, function(error, charge){
callback(error, charge);
});
};
var createStripeChargeSync = Meteor.wrapAsync(createStripeChargeAsync);
var submitOrder = function(ShoppingCartObject){
check(ShoppingCartObject, Object);
var customer = createStripeCustomerSync(ShoppingCartObject);
console.log("customer: ", customer);
var charge = createStripeChargeSync(customer, ShoppingCartObject);
console.log("charge: ", charge);
var data = _.omit(ShoppingCartObject, '_id');
var setHash = { $set: data };
ShoppingCarts.update({_id: ShoppingCartObject._id}, setHash);
};