手把手架构Express划分Router、Controller、Service和Middleware

💌手把手架构Express划分Router、Controller、Service和Middleware

背景👹

express框架在node中是使用频率最高的,简单易上手,如果不合理的控制各个模块的划分,随着业务代码增多,项目就会变得难以维护(屎山💩)。

在写了多个屎山之后,我逐渐学习到了如何划分项目结构,合理拆分业务代码😹,极大的减少了屎山💩的出现

本文将介绍一种常见的 Express 应用结构:通过路由(Router)、控制器(Controller)、服务(Service)和中间件(Middleware)进行模块划分。

为什么要划分路由、控制器、服务和中间件?🙈

具体来说:

  • 路由(Router) 就像是马路,它为请求提供了道路(路径)和方向(HTTP 方法),决定了请求会走哪条路,怎么走。
  • 控制器(Controller) 就像是交警,它处理来自路上(即客户端)的请求,确保车辆(请求)按正确的规则(业务逻辑)走,并且最终交付正确的结果(响应)。交警(控制器)可能会根据需要协调不同的司机(服务层)来完成任务。
  • 服务(Service) 就像是司机,负责实际的操作和执行任务,比如开车(处理核心业务逻辑)。司机会根据道路(控制器的指示)完成具体的工作,可能需要与外部环境(数据库、API 等)互动。
  • 中间件(Middleware) 就像是红绿灯路障,它们在车辆(请求)到达目标之前,提供额外的功能,比如控制通行(权限验证、日志记录等),确保路上顺畅或者在需要时拦停车辆,阻止不符合规则的请求继续前行。

通过这种分层设计,代码的逻辑变得清晰,每一层都有明确的责任,降低了模块间的耦合度,方便后期的维护和扩展。

Express 项目结构设计🙉

为了帮助大家更好地理解如何划分这些层次,我们将构建一个简单的任务管理 API,功能包括获取任务列表和创建任务。以下是我们的项目结构:

your_project/
│── public/ 静态文件目录
├── src/
│   ├── controllers/
│   │   ├── taskController.js      # 处理请求的控制器
│   ├── services/
│   │   ├── taskService.js         # 业务逻辑
│   ├── routes/
│   │   ├── taskRoutes.js          # 路由
│   ├── middlewares/
│   │   ├── authMiddleware.js      # 中间件
│   ├── models/
│   │   ├── taskModel.js           # 数据模型(如 MongoDB model)
│   ├── app.js                     # Express 应用入口
│   └── config.js                  # 配置文件(如数据库连接等)
├── node_modules/
└── package.json

代码实现🙊

app.js - 应用入口文件

app.js 是 Express 应用的核心,负责加载路由和中间件,启动服务器。

const express = require("express");
const bodyParser = require("body-parser");
const taskRoutes = require("./routes/taskRoutes");
const cors = require("cors");
const app = express();
// 处理跨域
app.use(cors())
// 处理json请求
app.use(express.json())
// 处理表单类型
app.use(express.urlencoded({ extended: false }))
// 静态文件目录
app.use(express.static("./public"))
​
// 加载任务路由
app.use("/tasks", taskRoutes);
​
// 错误处理中间件
app.use((err, req, res, next) => {
  console.error(err);
  res.status(500).json({ message: "Something went wrong" });
});
​
// 启动服务器
const port = 3000;
app.listen(port, () => {
  console.log(`Server is running on http://localhost:${port}`);
});
routes/taskRoutes.js - 路由层😺

路由定义了请求路径和方法,它将请求委托给控制器处理。

const express = require("express");
const router = express.Router();
const taskController = require("../controllers/taskController");
const authMiddleware = require("../middlewares/authMiddleware");
​
// 路由:获取所有任务
router.get("/", authMiddleware, taskController.getAllTasks);
​
// 路由:创建任务
router.post("/", authMiddleware, taskController.createTask);
​
module.exports = router;
controllers/taskController.js - 控制器层😸

控制器负责处理请求,协调服务层的业务逻辑,并将处理结果返回客户端。

const taskService = require("../services/taskService");
​
const taskController = {
  async getAllTasks(req, res, next) {
    try {
      const tasks = await taskService.getAllTasks();
      res.status(200).json(tasks);
    } catch (error) {
      next(error); // 错误处理传递给错误处理中间件
    }
  },
​
  async createTask(req, res, next) {
    try {
      const taskData = req.body;
      const newTask = await taskService.createTask(taskData);
      res.status(201).json(newTask);
    } catch (error) {
      next(error); // 错误处理传递给错误处理中间件
    }
  }
};
​
module.exports = taskController;
services/taskService.js - 服务层😹

服务层是核心业务逻辑处理的地方。它与数据库、外部 API 等交互,封装了业务操作。

const Task = require("../models/taskModel");
​
const taskService = {
  async getAllTasks() {
    try {
      const tasks = await Task.find(); // 假设使用 MongoDB 查询所有任务
      return tasks;
    } catch (error) {
      throw new Error("Error fetching tasks");
    }
  },
​
  async createTask(taskData) {
    try {
      const newTask = new Task(taskData);
      await newTask.save();
      return newTask;
    } catch (error) {
      throw new Error("Error creating task");
    }
  }
};
​
module.exports = taskService;
models/taskModel.js - 数据模型层😻

在这里,我们定义了任务的数据结构,假设使用 MongoDB 作为数据库。

const mongoose = require("mongoose");
​
const taskSchema = new mongoose.Schema({
  title: {
    type: String,
    required: true,
  },
  description: {
    type: String,
    required: true,
  },
  status: {
    type: String,
    default: "pending",
  },
});
​
const Task = mongoose.model("Task", taskSchema);
​
module.exports = Task;
middlewares/authMiddleware.js - 中间件层😼

中间件负责在请求到达路由之前执行特定的任务,如身份验证、日志记录等。

const authMiddleware = (req, res, next) => {
  // 假设我们做简单的身份验证
  const authHeader = req.headers.authorization;
​
  if (!authHeader || authHeader !== "Bearer your-token") {
    return res.status(403).json({ message: "Unauthorized" });
  }
​
  next(); // 继续处理请求
};
​
module.exports = authMiddleware;

错误处理😽

通过在 app.js 中定义全局的错误处理中间件,我们可以确保在应用发生任何错误时,客户端都能收到一致的错误响应。这种做法提高了代码的可维护性。

app.use((err, req, res, next) => {
  console.error(err);
  res.status(500).json({ message: "Something went wrong" });
});

总结🙀

通过将 Express 应用中的功能按路由、控制器、服务和中间件进行模块化,我们实现了一个清晰的架构。每一层都有明确的职责,互相之间的耦合度较低,方便后期的扩展和维护。具体来说:

  • 路由(Router) :负责定义路径和 HTTP 方法。(马路)
  • 控制器(Controller) :负责处理请求和响应,调用服务层的业务逻辑。(交警)
  • 服务(Service) :封装了核心业务逻辑,负责与数据库或外部 API 的交互。(司机)
  • 中间件(Middleware) :提供额外的功能,如身份验证、请求日志等。(红绿灯路障)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值