Node.js Express:如何将应用程序实例传递到来自不同文件的路由?

Node.js Express:如何将应用程序实例传递到来自不同文件的路由?,node.js,express,Node.js,Express,我想将我的路由拆分为不同的文件,其中一个文件包含所有路由,另一个文件包含相应的操作。我目前有一个解决方案来实现这一点,但是我需要使应用程序实例成为全局的,以便能够在操作中访问它。 我当前的设置如下所示: app.js: var express = require('express'); var app = express.createServer(); var routes = require('./routes'); var controllers = require(

我想将我的路由拆分为不同的文件,其中一个文件包含所有路由,另一个文件包含相应的操作。我目前有一个解决方案来实现这一点,但是我需要使应用程序实例成为全局的,以便能够在操作中访问它。 我当前的设置如下所示:

app.js:

var express   = require('express');
var app       = express.createServer();
var routes    = require('./routes');

var controllers = require('./controllers');
routes.setup(app, controllers);

app.listen(3000, function() {
  console.log('Application is listening on port 3000');
});
routes.js:

exports.setup = function(app, controllers) {

  app.get('/', controllers.index);
  app.get('/posts', controllers.posts.index);
  app.get('/posts/:post', controllers.posts.show);
  // etc.

};
controllers/index.js:

exports.posts = require('./posts');

exports.index = function(req, res) {
  // code
};
controllers/posts.js:

exports.index = function(req, res) {
  // code
};

exports.show = function(req, res) {
  // code
};
但是,这个设置有一个大问题:我有一个数据库和一个应用程序实例需要传递给操作(controllers/*.js)。我能想到的唯一选择是,将这两个变量都设置为全局变量,这并不是一个真正的解决方案。我想将路线与动作分开,因为我有很多路线,并且希望它们位于中心位置


向操作传递变量但将操作与路由分离的最佳方法是什么?

对于数据库分离数据访问服务,它将使用简单API完成所有数据库工作,并避免共享状态


分离routes.setup看起来像是开销。我更愿意放置一个基于配置的路由。并使用.json或注释配置路由。

如我在评论中所说,您可以使用module.exports函数。函数也是一个对象,因此不必更改语法

app.js

var controllers = require('./controllers')({app: app});
controllers.js

module.exports = function(params)
{
    return require('controllers/index')(params);
}
控制器/index.js

function controllers(params)
{
  var app = params.app;

  controllers.posts = require('./posts');

  controllers.index = function(req, res) {
    // code
  };
}

module.exports = controllers;
var app = require('../app');

app.get('/', function(req, res, next) {
  res.render('index');
});

//require in some other route files...each of which requires app independently
require('./user');
require('./blog');

使用
req.app
req.app.get('somekey')

通过调用
express()
创建的应用程序变量在请求和响应对象上设置


请参阅:

Node.js支持循环依赖关系。
使用循环依赖关系而不是require(“./routes”)(应用程序)可以清理大量代码,并减少每个模块在其加载文件上的依赖性:


app.js

var app = module.exports = express(); //now app.js can be required to bring app into any file

//some app/middleware setup, etc, including 
app.use(app.router);

require('./routes'); //module.exports must be defined before this line

routes/index.js

function controllers(params)
{
  var app = params.app;

  controllers.posts = require('./posts');

  controllers.index = function(req, res) {
    // code
  };
}

module.exports = controllers;
var app = require('../app');

app.get('/', function(req, res, next) {
  res.render('index');
});

//require in some other route files...each of which requires app independently
require('./user');
require('./blog');

----2014年4月更新---
Express 4.0通过添加Express.router()方法修复了定义路由的用例!
文件-

来自新生成器的示例:
写入路由:

将其添加到应用程序中/为其命名:


仍然存在从其他资源访问应用程序的用例,因此循环依赖项仍然是一个有效的解决方案。

假设您有一个名为“contollers”的文件夹

在app.js中,您可以输入以下代码:

console.log("Loading controllers....");
var controllers = {};

var controllers_path = process.cwd() + '/controllers'

fs.readdirSync(controllers_path).forEach(function (file) {
    if (file.indexOf('.js') != -1) {
        controllers[file.split('.')[0]] = require(controllers_path + '/' + file)
    }
});

console.log("Controllers loaded..............[ok]");
exports.pinging = function(req, res, next){
    console.log("ping ...");
}
。。。而且

router.get('/ping', controllers.ping.pinging);
在您的控制器文件夹中,您将拥有包含以下代码的文件“ping.js”:

console.log("Loading controllers....");
var controllers = {};

var controllers_path = process.cwd() + '/controllers'

fs.readdirSync(controllers_path).forEach(function (file) {
    if (file.indexOf('.js') != -1) {
        controllers[file.split('.')[0]] = require(controllers_path + '/' + file)
    }
});

console.log("Controllers loaded..............[ok]");
exports.pinging = function(req, res, next){
    console.log("ping ...");
}
就是这样….

或者就这样做:

var app = req.app
在用于这些路由的中间件内部。就像这样:

router.use( (req,res,next) => {
    app = req.app;
    next();
});
  • 要使所有控制器都可以访问您的db对象,而不必到处传递它:制作一个应用程序级中间件,将db对象附加到每个req对象,然后您可以在每个控制器中访问它
  • //app.js
    设db=…;//数据库对象已初始化
    const contextMiddleware=(请求、恢复、下一步)=>{
    要求db=db;
    next();
    };
    应用程序使用(上下文中间件);
    
  • 为了避免到处传递应用程序实例,请将路由传递到应用程序所在的位置
  • //routes.js这只是一个映射。
    exports.routes=[
    ['/',controllers.index],
    ['/posts',controllers.posts.index],
    ['/posts/:post',controllers.posts.show]
    ];
    //app.js
    var{routes}=require('./routes');
    routes.forEach(route=>app.get(…route));
    //您可以根据自己的需要进行定制,例如添加post请求
    
    最终的app.js:

    //app.js
    var express=需要(“express”);
    var app=express.createServer();
    设db=…;//数据库对象已初始化
    const contextMiddleware=(请求、恢复、下一步)=>{
    要求db=db;
    next();
    };
    应用程序使用(上下文中间件);
    var{routes}=require('./routes');
    routes.forEach(route=>app.get(…route));
    app.listen(3000,函数(){
    log('应用程序正在监听端口3000');
    });
    
    另一个版本:你可以根据自己的需要定制,比如添加post请求

    //routes.js这只是一个映射。
    让get=({path,callback})=>({app})=>{
    app.get(路径,回调);
    }
    让post=({path,callback})=>({app})=>{
    app.post(路径、回调);
    }
    让someFn=({path,callback})=>({app})=>{
    //…自定义逻辑
    app.get(路径,回调);
    }
    exports.routes=[
    获取({path:'/',回调:controllers.index}),
    post({path:'/posts',回调:controllers.posts.index}),
    someFn({path:'/posts/:post',callback:controllers.posts.show}),
    ];
    //app.js
    var{routes}=require('./routes');
    forEach(route=>route({app}));
    
    如果要在节点类型脚本中将应用程序实例传递给其他人

    选项1: 借助
    导入
    导入时

    然后导入并传递应用程序:

    import express, { Application } from 'express';
    
    const app: Application = express();
    import('./routes').then(m => m.routing(app))
    
    选项2:在
    类的帮助下

    // index.ts
    import express, { Application } from 'express';
    import { Routes } from './routes';
    
    
    const app: Application = express();
    const rotues = new Routes(app)
    ...
    
    在这里,我们将在Routes类的构造函数中访问应用程序

    // routes.ts
    import { Application } from 'express'
    import { categoryRoute } from '../routes/admin/category.route'
    import { courseRoute } from '../routes/admin/course.route';
    
    class Routes {
        constructor(private app: Application) {
            this.apply();
        }
    
        private apply(): void {
           this.app.use('/api/admin/category', categoryRoute)
           this.app.use('/api/admin/course', courseRoute)
        }
    }
    
    export { Routes }
    

    你的controllers.js看起来怎么样?也许你可以把它变成一个可以接收参数的函数(而不是对象)。require('controllers')需要controllers/index.js。但是,函数不起作用,因为我在路由中使用对象(请参见routes.js),因此无法向它传递参数,即使它是一个函数。您对数据访问服务是什么意思?看起来怎么样?我的real routes.js文件要大得多,并且使用了express namespaces模块。如何将路由与操作分开?在函数中返回一个对象可以吗?还是按照示例中的方法设置方法更好?我认为这两种方法都可以。因为我有很多方法,我更喜欢将它们设置为对象,而不是手动设置。当我只是返回对象时,这会起作用,但是是否有一个更平坦的解决方案?我的实际方法会缩进两次…不确定我是否理解您的意思,但我想您可以将实现移到
    controllers
    函数之外,比如: