请批评以下处理Meteor错误的方法:
Meteor上Meteor.wrapAsync()
方法的一个常见问题是它似乎没有从外部API返回实际错误:
https://github.com/meteor/meteor/issues/2774
1。使用wrapAsync()
的示例我正在使用一个简单的API来获取美国邮政编码并返回位置信息:
/server/methods.js
var getLocationAsync = function(zipcode, callback){
HTTP.call("GET", "http://api.zippopotam.us/us/" + zipcode, function(error, result) {
callback(error,result);
});
};
var getLocationWithWrap = Meteor.wrapAsync(getLocationAsync);
Meteor.methods({
getLocationWithWrap: function(zipcode){
return getLocationWithWrap(zipcode);
}
});
如果你这样做
Meteor.call("getLocationWithWrap", "94043", function(error, result){
if(error){
console.log("here is the error: ", error)
} else {
console.log("success: ", result);
}
})
你得到了适当的回应。但如果您传入无效的邮政编码:
Meteor.call("getLocationWithWrap", "940", function(error, result){
if(error){
console.log("here is the error: ", error)
} else {
console.log("success: ", result);
}
})
你只得到一个没有意义的通用Internal server error [500]
。
2。使用try / catch的示例(请参阅代码注释)
Meteor.methods({
getLocationWithWrapTryCatch: function(zipcode){
try {
return getLocationWithWrap(zipcode);
} catch(error){
// the error object just contains a 'stack' key
// and the value is difficult to use
// but the error is a 404 rather than a 500
throw new Meteor.Error(error.stack);
}
}
});
这样做的:
Meteor.call("getLocationWithWrapTryCatch", "940", function(error, result){
if(error){
console.log("here is the error: ", error)
} else {
console.log("success: ", result);
}
})
会导致难以解析的错误对象。
第3。使用@faceyspacey代码的示例
用户@faceyspacey编写了一个他称为makeAsync
的函数(我已将名称更改为makeSync
,因为他的代码采用异步函数并允许您以同步方式编写)。 / p>
它的作用是返回一个对象:
{error: error, data: data}
error
的值是外部API返回的实际错误。如果error
的值为null
,则data
的值将是外部API返回的数据。
/server/methods.js
Meteor.makeSync = 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;
};
};
var getLocationAsync = function(zipcode, callback){
HTTP.call("GET", "http://api.zippopotam.us/us/" + zipcode, function(error, result) {
callback(error,result);
});
};
var getLocationWithMakeSync = Meteor.makeSync(getLocationAsync);
Meteor.methods({
getLocationWithMakeSync: function(zipcode){
var result = getLocationWithMakeSync(zipcode);
if( result.error === null ){
return result.data;
} else {
throw new Meteor.Error(result.error.response.statusCode, "Zipcode cannot be found.");
}
},
});
现在你做的时候
Meteor.call("getLocationWithWrap", "94043", function(error, result){
if(error){
console.log("here is the error: ", error)
} else {
console.log("success: ", result);
}
});
您将获得从外部API返回的实际错误或无错结果。
我个人更喜欢第三种方法,因为您可以从外部API中使用实际的错误对象。我在这里错过了什么吗?使用外部API时是否有更好的方法来处理异步错误?
答案 0 :(得分:1)
@ faceyspacey的做法是我认为最好的方式。如果你看一下wrapAsync的源代码,它就非常相似(https://github.com/meteor/meteor/blob/832e6fe44f3635cae060415d6150c0105f2bf0f6/packages/meteor/helpers.js#L90)。该方法也用于几个外部包中。
答案 1 :(得分:1)
我来到这里遇到同样的麻烦:抛出的错误包含堆栈跟踪而不是原始错误。事实证明,原始错误被用作包含堆栈跟踪的对象的原型,但是:
https://github.com/meteor/meteor/issues/2774#issuecomment-70710564
......所有预期的属性都在那里,但它们都在 错误对象的原型而不是对象本身。查看 这个,在catch中添加
for (var key in e) { console.log(e, e[key]); }
块。
我测试了它,当然,它确实有效。