Nodejs中Router和Controller的紧耦合及一般做法探讨

Nodejs中Router和Controller的紧耦合及一般做法探讨

N-Blog的教程,和网上大多数主流教程,Router和Controller紧密耦合。虽然Router也是Controller的一部分,但是这样看怎么样也不是很优雅。
所以一般而言,都会怎么做?没有一个清晰的路由表很不爽的。
我目前的做法是将代码导出模块,然后在路由表传入。

这是routers/index.js

var Auth = require('../controller/authorization'),
    ArticleHandler = require('../controller/articles');

module.exports = function(app) { // router of index app.get(’/’, function(req, res){res.end(“Hello world!”)});

// router of /article
app.get('/articles', ArticleHandler.list_articles);
app.post('/articles', Auth.auth, ArticleHandler.add_article);

// router of /article/(.*)
app.put('/articles/:id', Auth.auth, ArticleHandler.modify_article);
app.get('/articles/:id', ArticleHandler.get_a_article);
app.delete('/articles/:id', Auth.auth, ArticleHandler.remove_article);

// router of /api-auth
app.post('/api-auth', Auth.get_token);

// router of /tags
app.get('/tags', function(req, res){});
// todo

};

然后controller里有articles.jsauthorization.js
articles.js为例,里面是一个Article类,然后暴露Article的接口。

var Article = require('../models/articles'),
    User = require('../models/users'),
    Auth = require('authorization');


function ArticleHandler() {
    //Article Handlers
}

ArticleHandler.list_articles = function(req, res) {
    // some statements
};

// Others

module.exports = ArticleHandler;

感觉比较蛋疼的。

不知你们的通用做法是?


8 回复

Node.js 中 Router 和 Controller 的紧耦合及一般做法探讨

在 Node.js 开发中,Router 和 Controller 的紧密耦合是一个常见的问题。尽管 Router 本身可以被视为 Controller 的一部分,但这种紧耦合的方式使得代码难以维护和扩展。本文将探讨如何通过解耦 Router 和 Controller 来提高代码的可维护性和可读性。

当前的实现方式

当前的实现方式是将 Router 和 Controller 紧密耦合在一起,如以下示例:

// routers/index.js
var Auth = require('../controller/authorization'),
    ArticleHandler = require('../controller/articles');

module.exports = function(app) {
    // router of index
    app.get('/', function(req, res){res.end("Hello world!")});

    // router of /article
    app.get('/articles', ArticleHandler.list_articles);
    app.post('/articles', Auth.auth, ArticleHandler.add_article);

    // router of /article/(.*)
    app.put('/articles/:id', Auth.auth, ArticleHandler.modify_article);
    app.get('/articles/:id', ArticleHandler.get_a_article);
    app.delete('/articles/:id', Auth.auth, ArticleHandler.remove_article);

    // router of /api-auth
    app.post('/api-auth', Auth.get_token);

    // router of /tags
    app.get('/tags', function(req, res){});
    // todo
};

controllers/articles.js 中,我们定义了一个 ArticleHandler 类来处理与文章相关的请求:

// controllers/articles.js
var Article = require('../models/articles'),
    User = require('../models/users'),
    Auth = require('../controller/authorization');

function ArticleHandler() {
    // Article Handlers
}

ArticleHandler.list_articles = function(req, res) {
    // some statements
};

ArticleHandler.add_article = function(req, res) {
    // some statements
};

ArticleHandler.modify_article = function(req, res) {
    // some statements
};

ArticleHandler.get_a_article = function(req, res) {
    // some statements
};

ArticleHandler.remove_article = function(req, res) {
    // some statements
};

module.exports = ArticleHandler;

解耦 Router 和 Controller

为了更好地解耦 Router 和 Controller,我们可以使用 Express Router 来创建独立的路由处理器。这样每个路由都可以独立管理其逻辑,而不必依赖于特定的 Controller。

首先,创建一个独立的路由处理器文件 routes/articles.js

// routes/articles.js
const express = require('express');
const router = express.Router();
const ArticleHandler = require('../controller/articles');

router.get('/articles', ArticleHandler.list_articles);
router.post('/articles', ArticleHandler.add_article);
router.put('/articles/:id', ArticleHandler.modify_article);
router.get('/articles/:id', ArticleHandler.get_a_article);
router.delete('/articles/:id', ArticleHandler.remove_article);

module.exports = router;

然后,在主路由器文件 routers/index.js 中引入这些独立的路由处理器:

// routers/index.js
const express = require('express');
const app = express();
const articlesRouter = require('./articles');

app.use('/articles', articlesRouter);

app.get('/', function(req, res){res.end("Hello world!")});
app.post('/api-auth', require('../controller/authorization').get_token);
app.get('/tags', function(req, res){});

module.exports = app;

这种方式不仅使代码更加清晰,还便于管理和扩展。每个路由处理器都独立管理自己的逻辑,而不需要依赖于特定的 Controller。

总结

通过将 Router 和 Controller 解耦,我们可以提高代码的可维护性和可读性。使用独立的路由处理器文件可以使每个路由逻辑更加清晰,并且便于管理和扩展。希望这种做法能帮助你更好地组织你的 Node.js 应用程序。


另外callback真是忧伤,让写出来的代码很脏,也不算优雅。
不过令人欣慰的是有中间件这个东西。要不然更蛋疼了。

没人鸟我=-=

乍一看这么写并没有什么不好的啊?不知道你哪里不满意~

callback的嵌套问题,可以交个promise来解决吧~

controller这个东西除了组织代码没看出来有什么用,组织代码可以用命名空间或者子目录, web框架只需要router,handle就可以了

一个handle一个文件,get/post/delete都是里面的方法handle多了可以分子目录存放,route独立出来做配置文件,就一个{’/xxx’:'ooHandle}就行了象express还有楼主这种路由与代码混在一起的,重构起来很麻烦

在Node.js项目中,RouterController的耦合问题是一个常见的设计挑战。为了提高代码的可维护性和扩展性,可以采取以下方法来解耦这两个部分。

通用做法:使用中间件和独立的控制器

  1. 创建一个独立的路由文件,其中只定义路由而不直接调用控制器。
  2. 在控制器文件中,提供与HTTP请求对应的处理逻辑。

示例代码

假设我们有一个简单的博客应用,其中包含文章相关的API。以下是重构后的代码:

1. 路由文件 routers/articleRoutes.js
const express = require('express');
const articleRouter = express.Router();
const articleController = require('../controllers/articleController');

articleRouter.route('/')
    .get(articleController.listArticles)
    .post(articleController.addArticle);

articleRouter.route('/:id')
    .get(articleController.getArticle)
    .put(articleController.updateArticle)
    .delete(articleController.deleteArticle);

module.exports = articleRouter;
2. 控制器文件 controllers/articleController.js
const Article = require('../models/articleModel');
const { checkAuth } = require('../middleware/authMiddleware');

exports.listArticles = async (req, res) => {
    const articles = await Article.find();
    res.json(articles);
};

exports.addArticle = async (req, res) => {
    const { title, content } = req.body;
    const newArticle = new Article({ title, content });
    await newArticle.save();
    res.status(201).json(newArticle);
};

exports.getArticle = async (req, res) => {
    const { id } = req.params;
    const article = await Article.findById(id);
    if (!article) return res.status(404).send('Article not found');
    res.json(article);
};

exports.updateArticle = async (req, res) => {
    const { id } = req.params;
    const { title, content } = req.body;
    const updatedArticle = await Article.findByIdAndUpdate(id, { title, content }, { new: true });
    if (!updatedArticle) return res.status(404).send('Article not found');
    res.json(updatedArticle);
};

exports.deleteArticle = async (req, res) => {
    const { id } = req.params;
    const deletedArticle = await Article.findByIdAndDelete(id);
    if (!deletedArticle) return res.status(404).send('Article not found');
    res.status(204).send();
};
3. 主应用文件 app.js
const express = require('express');
const app = express();
const articleRoutes = require('./routers/articleRoutes');
const authRoutes = require('./routers/authRoutes');

app.use(express.json());

app.use('/articles', articleRoutes);
app.use('/auth', authRoutes);

app.listen(3000, () => {
    console.log('Server running on port 3000');
});

通过这种方式,Router文件仅负责定义路由和传递给控制器,而控制器则专注于业务逻辑。这使得代码更易于维护和扩展。

回到顶部