我正在将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。 谢谢你的帮助
答案 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进行交互。您将成功或错误返回给客户端。
所以它总体上看起来像......
Meteor.call
来呼叫服务器,并将令牌与任何其他相关信息一起传递。 StripeSync
包和try/catch
块与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