隨著你的 Express 應用變得越來越大,所有的路由和中間件都寫在一個文件里會變得難以管理。這時候就需要將代碼進行拆分和組織。此外,一個健壯的后端應用必須能夠優雅地處理錯誤和一些常見的 Web 開發問題,比如跨域。
路由模塊化 (express.Router
):
express.Router
是 Express 提供的一個迷你應用,它有自己的中間件和路由。你可以把處理某個特定資源的路由(比如所有用戶相關的路由)放到一個單獨的文件中,然后像中間件一樣將其掛載到主應用上。這就像在廚房里為不同的菜品(資源)設立了專門的操作臺(路由文件),每個操作臺有自己的工作流程,但它們最終都屬于整個廚房(主應用)。
創建一個新的文件,比如 routes/users.js
:
// routes/users.js
const express = require('express');
const router = express.Router(); // 創建一個 Router 實例// 這里可以定義用戶相關的中間件,只應用于本路由文件中的路由
// router.use((req, res, next) => { console.log('用戶路由中間件'); next(); });// 定義用戶相關的路由
router.get('/', (req, res) => {// 處理獲取所有用戶的邏輯res.send('獲取所有用戶');
});router.get('/:userId', (req, res) => {const userId = req.params.userId;// 處理獲取單個用戶的邏輯res.send(`獲取用戶 ID: ${userId}`);
});router.post('/', (req, res) => {// 處理創建用戶的邏輯res.send('創建新用戶');
});// ... 其他用戶相關的路由 (PUT, DELETE)module.exports = router; // 導出 router 實例 (CommonJS 方式)// 如果使用 ES Modules:
// export default router;
在你的主應用文件 app.js
中導入并使用這個路由模塊:
// app.js
const express = require('express');
const app = express();
const port = 3000;// 導入用戶路由模塊
const usersRouter = require('./routes/users');
// const usersRouter from './routes/users.js'; // ES Modules// ... 其他中間件 (如 body-parser)// 將用戶路由模塊掛載到 /api/users 路徑下
app.use('/api/users', usersRouter);// ... 其他路由和中間件// 啟動服務器
app.listen(port, () => {console.log(`應用運行在 http://localhost:${port}`);
});// 現在訪問 /api/users 會由 usersRouter 處理
// 訪問 /api/users/123 會由 usersRouter.get('/:userId', ...) 處理
錯誤處理中間件:
在 Express 中,錯誤處理中間件有四個參數:(err, req, res, next)
。當你在任何路由或普通中間件中調用 next(err)
并傳入一個錯誤對象時,Express 會跳過后續的路由和中間件,直接進入錯誤處理中間件。這就像廚房里某個環節出了問題(比如菜燒焦了),不用繼續整個流程,直接通知服務員(調用錯誤處理中間件)去處理這個“異常訂單”。
通常,你會在所有路由和普通中間件的后面定義錯誤處理中間件,以捕獲所有未被處理的錯誤。
// app.js (接著上面的代碼)// ... 所有路由和普通中間件 ...// 404 錯誤處理 (放在所有有效路由之后)
app.use((req, res, next) => {res.status(404).send("對不起,找不到該頁面!");
});// 錯誤處理中間件 (四個參數)
app.use((err, req, res, next) => {console.error("服務器端錯誤:", err.stack); // 打印錯誤堆棧到服務器控制臺res.status(500).send("服務器內部出錯!"); // 向客戶端發送 500 狀態碼和錯誤信息
});// 在路由中模擬錯誤
app.get('/error-test', (req, res, next) => {// 模擬一個錯誤const myError = new Error("這是一個測試錯誤");next(myError); // 將錯誤傳遞給錯誤處理中間件
});
常用的第三方中間件:
Express 的生態系統非常豐富,有很多優秀的第三方中間件可以方便地集成。
morgan
(日志記錄): 記錄所有收到的 HTTP 請求信息,對于調試和監控非常有幫助。就像餐廳里的訂單記錄系統。- 安裝:
npm install morgan
- 使用:
const morgan = require('morgan'); app.use(morgan('dev'));
(dev 是預設的日志格式)
- 安裝:
cors
(跨域資源共享): 處理瀏覽器的同源策略限制,允許來自不同域的前端應用訪問你的后端 API。這就像允許來自不同地區的顧客在你的餐廳點餐。- 安裝:
npm install cors
- 使用:
const cors = require('cors'); app.use(cors());
(允許所有跨域請求,也可以配置更精細的規則)
- 安裝:
// app.js (接著上面的代碼)const morgan = require('morgan');
const cors = require('cors');// 使用 morgan 中間件記錄日志
app.use(morgan('dev'));// 使用 cors 中間件處理跨域
app.use(cors());// ... 其他路由和中間件 ...
小例子:模塊化路由和全局錯誤處理
請參考上面關于 express.Router
和錯誤處理中間件的代碼示例,將它們集成到一個完整的 Express 應用中。
小結: 使用 express.Router
可以將復雜的路由邏輯拆分到單獨的文件中,提高代碼的可組織性。錯誤處理中間件是捕獲和處理應用錯誤的統一方式。morgan
和 cors
是兩個非常常用的第三方中間件,分別用于日志記錄和跨域處理。
練習:
- 在你的 Express 項目中,為之前的“書籍”資源創建一個單獨的路由文件 (
routes/books.js
)。 - 在
routes/books.js
中,使用express.Router()
定義至少兩個路由(例如 GET / 和 GET /:bookId)。 - 在主應用文件
app.js
中導入routes/books.js
并將其掛載到/api/books
路徑下。 - 在主應用中添加一個 404 錯誤處理中間件(放在所有有效路由之后)。
- 在主應用中添加一個全局錯誤處理中間件,當接收到錯誤時,記錄錯誤到控制臺并向客戶端發送 500 狀態碼。
- 安裝并使用
morgan
中間件記錄所有請求日志。 - 安裝并使用
cors
中間件,允許所有來源的跨域請求。