不解决或拒绝诺言是否安全? [英] Is it safe to not resolve or reject a promise
问题描述
想象一下一个Web应用程序,它的路由需要在继续操作之前检查是否允许用户访问给定资源. 已验证"检查依赖于数据库调用.
在每条路线中,我可能都有:
authorizeOwnership(req, res)
.then(function() {
// do stuff
res.send(200, "Yay");
});
我希望authorizeOwnership()
函数处理403(拒绝访问)和500(例如数据库查询错误)响应,以便每个路由都不需要显式执行.
我有一个可以查询数据库以检查所有权的功能.
function confirmOwnership(resourceId, userId) {
// SequelizeJS... returns a bluebird promise
return Resource.find({
where: {id: resourceId, userId: userId}
})
.then(function(resource) {
if(!resource) {
return null; // no match for this resource id + user id
} else {
return resource;
}
});
}
然后在authorizeOwnership
中使用它:
function authorizeOwnership(req, res) {
var rid = parseInt(req.params.rid, 10),
userId = parseInt(req.authInfo.userid, 10);
return new Promise(function(resolve, reject) {
confirmOwnership(rid, userId)
.then(function(resource) {
if(resource === null) {
res.send(403, "Forbidden");
// Note: we don't resolve; outer handler will not be called
} else {
resolve(resource);
}
})
.catch(function(err) {
console.log(err);
res.send(500, "Server error");
// Note: we don't resolve; outer handler will not be called
});
});
}
在这种情况下,我故意不在某些代码路径中调用reject()
或resolve()
.如果这样做,那么我的外部"路由逻辑(调用authorizeOwnership()
的代码)将变得更加复杂,因为它必须处理错误(使用.catch()
或使用null
检入.then()
)./p>
两件事让我有点紧张:
-
在错误情况下永远不会解决
authorizeOwnership()
返回的承诺吗?会导致延迟或内存泄漏吗? -
从逻辑上讲,将null解析为
confirmOwnership()
时说找不到匹配的资源",然后将其视为authorizeOwnership()
中的错误,这是否合理?当没有匹配的资源时,我的第一次尝试就拒绝了confirmOwnership()
中的诺言,但这使事情变得更加复杂,因为很难区分此错误(403例)和实际错误(500例).
在错误情况下永远不能解决authorizeOwnership()返回的诺言吗?它会导致延迟或内存泄漏吗?
Is it OK for the promise returned by authorizeOwnership() to never be resolved in error scenarios? Will it cause a delay or a memory leak?
Yes, it is safe to not resolve a Bluebird promise (and to be fair, any other implementation I've checked -pretty pictures here). It has no global state on its own.
The question of whether or not it's good practice is different. It's like a synchronous break
in a sense. Personally I'm not a fan.
Is it logically sound to resolve confirmOwnership() with null to say "no matching resource found" and then treat that as an error in authorizeOwnership()?
This depends on your API. It's again an opinion. It works, but I probably would not return null but indicate failure if the case is exceptional. You can distinguish the rejection using an error object. You can reject with an AuthorizationError
object you create for example. Note Bluebird also supports typed catches.
Something like:
// probably shouldn't send the response to authorizeOwnership but use it externally
// to be fair, should probably not take req either, but rid and userid
var authorizeOwnership = Promise.method(function(req) {
var rid = Number(req.params.rid),
userId = Number(req.authInfo.userid;
return confirmOwnership(rid, userId); // return the promise
});
});
function ServerError(code,reason){
this.name = "ServerError";
this.message = reason;
this.code = code;
Error.captureStackTrace(this); // capture stack
}
var confirmOwnership = Promise.method(function(resourceId, userId) {
// SequelizeJS... returns a bluebird promise
return Resource.find({
where: {id: resourceId, userId: userId}
})
.then(function(resource) {
if(!resource) {
throw new ServerError(403,"User not owner"); // promises are throw safe
}
return resource;
});
});
Next, in your server, you can do something like:
app.post("/foo",function(req,res){
authorizeOwnership(req).then(function(){
res.send(200, "Owner Yay!");
}).catch(ServerError,function(e){
if(e.code === 403) return res.send(403,e.message);
return res.send(500,"Internal Server Error");
});
});
Note: you're also using the deferred anti pattern in your code. There is no need to do new Promise(function(...){
in your code, you can simply return the promise.
这篇关于不解决或拒绝诺言是否安全?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!