我使用回调在redis db async上设置了一些ip。
我试图捕获错误并通过express将其发送到我的错误处理程序中间件。
我在select方法上故意生成错误,但它并没有发现我的错误。
请参阅以下代码:
module.exports = (req, res, next) => {
const redis = require('redis')
const client = redis.createClient()
try {
client.select('2d', (err) => { // instead of 2 number, i use '2d' string, to generate an error on purpose
const ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress
client.set(ip, true, 'EX', 120, (err, rep) => {
return next()
})
})
} catch (err) {
err.type = 'SilentSystem'
next(err)
}
}
答案 0 :(得分:3)
从documentation of the redis npm package开始,很明显它使用标准的Node-style回调。在标准的Node-style回调中,传递给您提供的回调的第一个参数是错误或null
;这就是报告错误的地方和方式。 (您甚至在代码中定义了一个名为err
的参数。)它们无法被try/catch
捕获,因为控件已经超出了try/catch
(实际上已经超出了module.exports = (req, res, next) => {
const redis = require('redis')
const client = redis.createClient()
client.select('2d', (err) => { // instead of 2 number, i use '2d' string, to generate an error on purpose
if (err) {
// Handle error here
err.type = 'SilentSystem'
next(err)
} else {
// Handle success here
const ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress
client.set(ip, true, 'EX', 120, (err, rep) => {
if (err) {
err.type = 'SilentSystem'
next(err)
} else {
next()
}
})
}
})
}
在错误发生之前很久就发生了它的功能。
所以你要像这样处理它:
if(err)
你在评论中说过:
我的实际代码有点复杂,所以我试图避免调用以避免使用
next(err)
重复调用try
和client.select
。在这里处理错误的更好方法(更简洁)是什么?
不幸的是,这就是Node风格回调的本质。一种选择是给你自己一个过滤功能,你通过所有这些结果,所以你的常见错误处理代码就在那里。
但是:你可能会考虑使用一个“宣传”节点式回调的lib,这样你就可以使用promises,完成它们的链接机制,使集中的错误处理成为可能。 (其中一个包是promisify
,但还有其他包。)对于client.set
,module.exports = (req, res, next) => {
const redis = require('redis')
const client = makeNiftyPromiseVersionOf(redis.createClient())
client.select('2d')
.then(data => {
const ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress
return client.set(ip, true, 'EX', 120)
})
.then(() => {
next()
})
.catch(err => {
err.type = 'SilentSystem'
next(err)
})
}
等的“已宣传”版本,该代码可能如下所示:
client.select
注意最后如何整合错误处理;如果then
中出现错误,则会跳过catch
回调并将控制传递给then
。如果没有,则会执行client.set
回调并执行catch
,并且其中的任何错误也会转到async
。
这也打开了使用ES2017的await
/ module.exports = (req, res, next) => {
(async () => {
const redis = require('redis')
const client = makeNiftyPromiseVersionOf(redis.createClient())
try {
const data = await client.select('2d');
const ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress
await client.set(ip, true, 'EX', 120)
next()
} catch (err) {
err.type = 'SilentSystem'
next(err)
}
})();
}
以同步方式编写异步代码的大门:
require
附注:我会删除导出函数的const redis = require('redis')
module.exports = {
// ...
}
调用 out ,而是在模块级别执行此操作:
setInterval(function(){
$("#irack").stop().animate({"left": -30}, 20)
},300);