尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

Node系列 · Express:路由

Node系列 · Express:路由 Node系列 · Express路由一个 Express 项目动辄几十上百个接口——全部堆在app.js里会迅速失控。express.Router()把路由按业务模块拆成独立文件是 Express 项目结构的标准做法。一、express.Router()是什么Router是带路径前缀的迷你 app——可以注册中间件、挂载路由、最后app.use()引入const express require(express); const router express.Router(); router.get(/users, listUsers); router.post(/users, createUser); module.exports router;挂载到主应用const userRoutes require(./routes/users); app.use(/api, userRoutes); // 现在 GET /api/users 触发 listUsers二、模块化路由拆分项目结构app.js routes/ ├── users.js ├── posts.js └── auth.js controllers/ ├── userController.js ├── postController.js └── authController.js2.1 路由文件routes/users.jsconst express require(express); const router express.Router(); const ctrl require(../controllers/userController); router.get(/, ctrl.list); router.get(/:id, ctrl.detail); router.post(/, ctrl.create); router.put(/:id, ctrl.update); router.delete(/:id, ctrl.remove); module.exports router;2.2 控制器controllers/userController.jsexports.list async (req, res, next) { try { const users await User.findAll(); res.json({ users }); } catch (err) { next(err); } }; exports.detail async (req, res, next) { try { const user await User.findByPk(req.params.id); if (!user) return res.status(404).json({ error: Not found }); res.json(user); } catch (err) { next(err); } }; exports.create async (req, res, next) { try { const user await User.create(req.body); res.status(201).json(user); } catch (err) { next(err); } }; exports.update async (req, res, next) { try { const [count] await User.update(req.body, { where: { id: req.params.id }, }); if (count 0) return res.status(404).json({ error: Not found }); res.json({ id: req.params.id, ...req.body }); } catch (err) { next(err); } }; exports.remove async (req, res, next) { try { const count await User.destroy({ where: { id: req.params.id } }); if (count 0) return res.status(404).json({ error: Not found }); res.status(204).end(); } catch (err) { next(err); } };2.3 主入口app.jsconst express require(express); const app express(); // 通用中间件 app.use(express.json()); app.use(require(morgan)(dev)); // 业务路由 app.use(/api/users, require(./routes/users)); app.use(/api/posts, require(./routes/posts)); app.use(/api/auth, require(./routes/auth)); // 404 错误处理 app.use((req, res) res.status(404).json({ error: Not found })); app.use((err, req, res, next) { console.error(err); res.status(500).json({ error: Server error }); }); app.listen(3000);每个业务模块自包含 router controller主入口只负责装配——单一职责。三、路由参数3.1 路径参数router.get(/users/:id, (req, res) { console.log(req.params.id); // 字符串 }); router.get(/posts/:postId/comments/:commentId, (req, res) { const { postId, commentId } req.params; });3.2 带正则约束router.get(/users/:id(\\d), (req, res) { // 只匹配数字 id }); router.get(/files/:filename(*), (req, res) { // filename 可以包含斜杠 });3.3 Query 参数router.get(/search, (req, res) { console.log(req.query); // { keyword: node, page: 2 } }); // GET /search?keywordnodepage23.4 三种参数的区别类型来源示例路径参数URL 路径段/users/:id→req.params.idQuery 参数URL?后/search?qx→req.query.qBody 参数请求体POST /api JSON →req.body四、route()链式调用同一路径不同方法用route()集中router.route(/users) .get(listUsers) .post(createUser) .put(updateAllUsers); // 批量更新 router.route(/users/:id) .get(detailUser) .put(updateUser) .patch(partialUpdateUser) .delete(removeUser);每条路径只写一次方法链式——便于看清对同一个资源的所有操作。五、路由级中间件可以给某个 router 单独挂中间件const router express.Router(); // 仅该 router 生效 router.use(requireAuth); router.get(/private/data, (req, res) { res.json({ secret: 只有登录用户能看到 }); });也可以给特定路径router.use(/admin, requireAdmin); router.get(/admin/users, listAllUsers);六、嵌套 routerRouter 可以嵌套const postRoutes require(./posts); const router express.Router(); router.use(/:postId/comments, postRoutes); // /api/posts/:postId/comments 触发 posts.js 里的 router app.use(/api/posts, router);适合复杂的多层资源路由。七、最佳实践场景推荐项目结构routes/controllers/分层路由命名复数资源名/users、/posts路径参数:id不要加类型前缀用:userId更好控制器函数try/catchnext(err)把错误传给错误中间件路由分组按业务模块/api/users、/api/posts鉴权路由级中间件router.use(requireAuth)八、小结express.Router()创建模块化路由——主入口只负责装配推荐结构routes/路由controllers/业务逻辑三种参数req.params路径/req.queryquery/req.bodybodyroute()链式同一资源的所有方法集中在一处路由级中间件用router.use(auth)只对该路由生效复杂项目用嵌套 router多层资源路径清晰
返回列表