在Web開發中,中間件(Middleware)是處理HTTP請求和響應的核心機制之一。EggJS基于Koa的洋蔥模型實現了高效的中間件機制,本文將深入探討中間件的執行原理、開發實踐以及常見問題解決方案。
一、中間件執行機制與洋蔥模型
1. 洋蔥模型解析
EggJS繼承自Koa的洋蔥模型,中間件按照“先進后出”的順序執行,形成一個類似洋蔥的結構:
// 中間件執行順序示例
app.use(async (ctx, next) => {console.log('Middleware 1 Start');await next();console.log('Middleware 1 End');
});app.use(async (ctx, next) => {console.log('Middleware 2 Start');await next();console.log('Middleware 2 End');
});// 請求處理流程輸出:
// Middleware 1 Start → Middleware 2 Start → Controller → Middleware 2 End → Middleware 1 End
執行特點:
- 請求從外到內穿過各層中間件
- 響應從內到外返回時執行剩余邏輯
- 支持異步操作(
async/await
)
二、開發常用中間件實戰
1. 日志記錄中間件
記錄請求基本信息與響應時間:
// app/middleware/access_log.js
module.exports = (options) => {return async (ctx, next) => {const start = Date.now();await next();const cost = Date.now() - start;ctx.logger.info(`${ctx.method} ${ctx.url} - ${ctx.status} [${cost}ms]`);};
};
2. 權限校驗中間件
JWT Token驗證示例:
// app/middleware/auth.js
const jwt = require('jsonwebtoken');module.exports = () => {return async (ctx, next) => {const token = ctx.get('Authorization');try {const decoded = jwt.verify(token, ctx.app.config.jwtSecret);ctx.state.user = decoded; // 用戶信息掛載到上下文await next();} catch (err) {ctx.status = 401;ctx.body = { message: 'Invalid token' };}};
};
3. 性能監控中間件
上報接口響應時間:
// app/middleware/performance.js
module.exports = () => {return async (ctx, next) => {const start = Date.now();await next();const cost = Date.now() - start;ctx.app.metrics.timing('http_request_duration', cost, {method: ctx.method,path: ctx.path,status: ctx.status});};
};
三、中間件配置策略
1. 全局中間件配置
在config/config.default.js
中啟用:
module.exports = {middleware: ['performance', 'accessLog'],// 中間件參數配置accessLog: {ignorePaths: ['/healthcheck']}
};
2. 路由級中間件配置
在路由文件中指定:
// app/router.js
module.exports = app => {const { router, middleware } = app;router.get('/admin',middleware.auth(), // 路由中間件controller.admin.index);
};
執行順序:
- 全局中間件按配置數組順序執行
- 路由級中間件在匹配到路由后執行
四、常見開發陷阱與規避
1. 忘記調用next()
錯誤示例:
module.exports = () => {return async (ctx) => { // 缺少next參數// 業務邏輯...// 未執行await next()};
};
后果:請求被掛起,后續中間件不執行
2. 異步操作處理不當
正確做法:
module.exports = () => {return async (ctx, next) => {await someAsyncTask(); // 必須await異步操作await next();};
};
3. 中間件順序錯誤
黃金法則:
- 通用中間件(如日志)放在前面
- 業務相關中間件(如權限)放在后面
4. 性能問題優化
避免在中間件中:
- 同步阻塞操作(如大文件讀取)
- 高頻的遠程調用(可改用緩存)
五、最佳實踐建議
- 職責單一:每個中間件只處理一個功能
- 合理分層:
- 全局層:日志、性能監控
- 路由層:權限校驗、參數校驗
- 錯誤處理:使用
try/catch
包裹核心邏輯 - 性能監控:關鍵中間件添加耗時統計
總結
中間件機制是EggJS框架的核心特性之一,合理使用中間件可以實現以下優勢:
- 功能解耦:分離業務與非業務邏輯
- 邏輯復用:通用功能全局生效
- 靈活擴展:按需組合不同中間件
下篇預告:數據庫操作與ORM實踐
下一篇將深入探討:
- MySQL基礎配置與多環境適配
- Sequelize模型定義與關聯關系
- 復雜查詢構建與性能優化
- 數據庫遷移與種子數據管理
正確理解和應用中間件,可以顯著提升EggJS應用的開發效率和可維護性。下一篇文章我們將深入探討《數據庫操作與ORM實踐》,解析如何在Egg中高效操作數據庫。歡迎在評論區留下你遇見的「中間件」設計經驗與挑戰,共同探討最佳實踐!