持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第7天,点击查看活动详情
王志远,微医前端技术部
先看应用
应用规则:
- 首先进行错误中间件注册(错误中间件区别普通中间件就在于它有四个参数)
app.use((err,req,res,next) => {
res.header('Content-Type','text/html;charset=utf-8');
res.end(err)
})
- 应用时,只要在执行
next函数时传递参数,就会执行到错误中间件的回调中,并且会将值传递给err
app.use(function (req,res,next){
let flag = Math.random() > 0.5;
if(flag){
return next('出错了');
}
next();
})
访问效果如下
实现思路
同样的,对错误中间件进行区别处理,判断逻辑
- 根据
route属性的有无判断是不是中间件 - 根据
fn.length是不是 4 判断是不是错误中间件 (函数的length属性是参数个数)
具体实现
改写 Router 的handle方法,注意两点:
- 如果 next 有参数,则查找错误中间件以执行
- 在执行中间件时要进行判断,从而避免执行了错误中间件
Router.prototype.handle = function(req, res, done) {
let { pathname } = url.parse(req.url);
let method = req.method.toLowerCase()
let idx = 0;
let removed = '';
const next = (err) => { // 中间件 和内部的 next 方法 出错都会走这个 next
if (idx >= this.stack.length) return done(); // 路由处理不了 传递给应用层
let layer = this.stack[idx++];
if (err) {
// 如果有错误 , 找错误处理中间件
if(!layer.route){ // 中间件
if(layer.handler.length === 4){
layer.handler(err,req,res,next)
}else{
next(err);
}
}else{ // 路由
next(err);
}
} else {
// 无论是路由还是中间件 前提是路径必须匹配
if (layer.match(pathname)) { // match 还没有更改
if (!layer.route) { // 没有说明是中间件
// 正常中间件不走错误
if(layer.handler.length !== 4){
layer.handle_request(req, res, next); // 直接执行中间件函数
}else{
next();
}
} else {
// 路由必须匹配方法
if (layer.route.methods[method]) { // 这个 next 可以让路由层扫描下一个 layer
layer.handle_request(req, res, next); // route.dispatch
} else {
next();
}
}
} else {
next();
}
}
}
next(); // 请求来了取出第一个执行
}