您现在的位置是:网站首页 > 中间件的执行顺序与控制文章详情
中间件的执行顺序与控制
陈川
【
Node.js
】
28533人已围观
5380字
中间件的概念与作用
Express中间件本质上是函数,能够访问请求对象(req)、响应对象(res)以及应用程序的请求-响应周期中的下一个中间件函数。这些函数可以执行以下操作:
- 修改请求和响应对象
- 结束请求-响应周期
- 调用堆栈中的下一个中间件
const express = require('express');
const app = express();
// 最简单的中间件示例
app.use((req, res, next) => {
console.log('Time:', Date.now());
next();
});
中间件的类型
Express中的中间件主要分为以下几种类型:
应用级中间件
使用app.use()或app.METHOD()绑定到app对象上的中间件:
// 对所有请求生效
app.use((req, res, next) => {
console.log('Application-level middleware');
next();
});
// 只对GET请求生效
app.get('/user', (req, res, next) => {
console.log('GET-specific middleware');
next();
});
路由级中间件
绑定到express.Router()实例上的中间件:
const router = express.Router();
router.use((req, res, next) => {
console.log('Router-level middleware');
next();
});
错误处理中间件
专门处理错误的中间件,需要四个参数:
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).send('Something broke!');
});
内置中间件
Express自带的中间件,如express.static:
app.use(express.static('public'));
第三方中间件
社区提供的中间件,如body-parser:
const bodyParser = require('body-parser');
app.use(bodyParser.json());
中间件的执行顺序
中间件的执行顺序完全取决于它们在代码中被定义的顺序。Express会按照中间件被添加的顺序依次执行它们:
app.use((req, res, next) => {
console.log('First middleware');
next();
});
app.use((req, res, next) => {
console.log('Second middleware');
next();
});
app.get('/', (req, res) => {
res.send('Hello World');
});
在这个例子中,控制台会先输出"First middleware",然后是"Second middleware",最后才会处理GET请求。
控制中间件流程
next()函数的作用
next()函数将控制权传递给下一个中间件。如果不调用next(),请求将会挂起:
app.use((req, res, next) => {
// 不调用next(),请求将不会继续
if (req.headers['x-auth']) {
next();
} else {
res.status(401).send('Unauthorized');
}
});
提前终止请求
可以在中间件中直接发送响应来终止请求链:
app.use((req, res, next) => {
if (!req.user) {
return res.status(401).send('Please login');
}
next();
});
错误处理流程
使用next(err)可以将错误传递给错误处理中间件:
app.get('/user/:id', (req, res, next) => {
User.findById(req.params.id, (err, user) => {
if (err) {
return next(err); // 跳转到错误处理中间件
}
res.send(user);
});
});
中间件的组合与模块化
可以将多个中间件组合成数组,这在路由处理中特别有用:
const logOriginalUrl = (req, res, next) => {
console.log('Request URL:', req.originalUrl);
next();
};
const logMethod = (req, res, next) => {
console.log('Request Type:', req.method);
next();
};
const logStuff = [logOriginalUrl, logMethod];
app.get('/user', logStuff, (req, res) => {
res.send('User Info');
});
异步中间件的处理
处理异步操作时,必须确保在异步操作完成后调用next():
app.use(async (req, res, next) => {
try {
const data = await someAsyncOperation();
req.data = data;
next();
} catch (err) {
next(err);
}
});
中间件的性能考虑
减少不必要的中间件
每个中间件都会增加请求处理时间,应该只包含必要的中间件:
// 只在开发环境使用日志中间件
if (process.env.NODE_ENV === 'development') {
app.use(morgan('dev'));
}
中间件的优化顺序
将最常用的路由放在前面,减少不必要的中间件执行:
// 静态文件路由放在前面
app.use(express.static('public'));
// 其他路由放在后面
app.use('/api', apiRouter);
常见中间件模式
认证中间件
典型的认证中间件实现:
const authMiddleware = (req, res, next) => {
const token = req.headers['authorization'];
if (!token) {
return res.status(401).json({ error: 'No token provided' });
}
try {
const decoded = jwt.verify(token, SECRET_KEY);
req.user = decoded;
next();
} catch (err) {
return res.status(403).json({ error: 'Invalid token' });
}
};
app.get('/profile', authMiddleware, (req, res) => {
res.json({ user: req.user });
});
请求数据处理中间件
处理请求数据的中间件组合:
app.use(express.json()); // 解析JSON body
app.use(express.urlencoded({ extended: true })); // 解析表单数据
app.use(cookieParser()); // 解析cookies
跨域处理中间件
自定义CORS中间件:
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
res.header('Access-Control-Allow-Headers', 'Content-Type');
next();
});
调试中间件执行
可以使用特殊的调试中间件来跟踪执行流程:
app.use((req, res, next) => {
console.log(`[${new Date().toISOString()}] ${req.method} ${req.path}`);
next();
});
app.use((req, res, next) => {
console.log('Request headers:', req.headers);
next();
});
高级中间件技巧
动态加载中间件
根据条件动态加载中间件:
const config = require('./config');
if (config.featureFlags.analytics) {
app.use(analyticsMiddleware());
}
中间件的条件执行
基于请求属性的条件执行:
app.use((req, res, next) => {
if (req.path.startsWith('/api')) {
console.log('API request detected');
}
next();
});
中间件的重写功能
修改请求或响应对象:
app.use((req, res, next) => {
// 添加自定义方法到response对象
res.jsonSuccess = (data) => {
res.json({ success: true, data });
};
next();
});
// 使用自定义方法
app.get('/data', (req, res) => {
res.jsonSuccess({ message: 'It works!' });
});
中间件的测试策略
编写可测试的中间件:
// 中间件函数
const loggerMiddleware = (req, res, next) => {
console.log(`Logged ${req.method} ${req.url}`);
next();
};
// 测试用例
test('logger middleware should call next', () => {
const req = { method: 'GET', url: '/test' };
const res = {};
const next = jest.fn();
loggerMiddleware(req, res, next);
expect(next).toHaveBeenCalled();
});
上一篇: 自定义中间件的开发方法