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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10090414/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 15:30:22  来源:igfitidea点击:

Express: How to pass app-instance to routes from a different file?

node.jsexpress

提问by Claudio Albertin

I want to split up my routes into different files, where one file contains all routes and the other one the corresponding actions. I currently have a solution to achieve this, however I need to make the app-instance global to be able to access it in the actions. My current setup looks like this:

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

app.js:

应用程序.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:

路线.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:

控制器/index.js:

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

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

controllers/posts.js:

控制器/posts.js:

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

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

However, this setup has a big issue: I have a database- and an app-instance I need to pass to the actions (controllers/*.js). The only option I could think of, is making both variables global which isn't really a solution. I want to separate routes from the actions because I have a lot of routes and want them in a central place.

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

What's the best way to pass variables to the actions but separate the actions from the routes?

将变量传递给动作但将动作与路线分开的最佳方法是什么?

回答by Feng

Use req.app, req.app.get('somekey')

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

The application variable created by calling express()is set on the request and response objects.

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

See: https://github.com/visionmedia/express/blob/76147c78a15904d4e4e469095a29d1bec9775ab6/lib/express.js#L34-L35

参见:https: //github.com/visionmedia/express/blob/76147c78a15904d4e4e469095a29d1bec9775ab6/lib/express.js#L34-L35

回答by Will Stern

Node.js supports circular dependencies.
Making use of circular dependencies instead of require('./routes')(app) cleans up a lot of code and makes each module less interdependent on its loading file:

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



路线/ index.js

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');



-----04/2014 update----------04/2014 更新-----


Express 4.0 通过添加 express.router() 方法修复了定义路由的用例!


文档-http://expressjs.com/4x/api.html#routerhttp://expressjs.com/4x/api.html#router

Example from their new generator:
Writing the route:
https://github.com/expressjs/generator/blob/master/templates/js/routes/index.js
Adding/namespacing it to the app: https://github.com/expressjs/generator/blob/master/templates/js/app.js#L24

来自他们新生成器的示例:
编写路由:
https: //github.com/expressjs/generator/blob/master/templates/js/routes/index.js
将其添加/命名为应用程序:https: //github.com /expressjs/generator/blob/master/templates/js/app.js#L24

There are still usecases for accessing app from other resources, so circular dependencies are still a valid solution.

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

回答by mihai

Like I said in the comments, you can use a function as module.exports. A function is also an object, so you don't have to change your syntax.

就像我在评论中所说的那样,您可以将函数用作 module.exports。函数也是一个对象,因此您不必更改语法。

app.js

应用程序.js

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

controllers.js

控制器.js

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

controllers/index.js

控制器/index.js

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

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

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

module.exports = controllers;

回答by asanchez

Or just do that:

或者只是这样做:

var app = req.app

inside the Middleware you are using for these routes. Like that:

在您用于这些路由的中间件内部。像那样:

router.use( (req,res,next) => {
    app = req.app;
    next();
});

回答by sully

  1. To make your db object accessible to all controllers without passing it everywhere: make an application-level middleware which attachs the db object to every req object, then you can access it within in every controller.
  1. 为了让所有控制器都可以访问您的 db 对象,而无需将其传递到任何地方:制作一个应用程序级中间件,将 db 对象附加到每个 req 对象,然后您可以在每个控制器中访问它。
// app.js
let db = ...;  // your db object initialized
const contextMiddleware = (req, res, next) => {
  req.db=db;
  next();
};
app.use(contextMiddleware);
  1. to avoid passing app instance everywhere, instead, passing routes to where the app is
  1. 避免在任何地方传递应用程序实例,而是将路由传递到应用程序所在的位置
// routes.js  It's just a mapping.
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));
// You can customize this according to your own needs, like adding post request

The final app.js:

最终的 app.js:

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

let db = ...;  // your db object initialized
const contextMiddleware = (req, res, next) => {
  req.db=db;
  next();
};
app.use(contextMiddleware);

var { routes }    = require('./routes');
routes.forEach(route => app.get(...route));

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

Another version: you can customize this according to your own needs, like adding post request

另一个版本:你可以根据自己的需要自定义这个,比如添加post请求

// routes.js  It's just a mapping.
let get = ({path, callback}) => ({app})=>{
  app.get(path, callback);
}
let post = ({path, callback}) => ({app})=>{
  app.post(path, callback);
}
let someFn = ({path, callback}) => ({app})=>{
  // ...custom logic
  app.get(path, callback);
}
exports.routes = [
  get({path: '/', callback: controllers.index}),
  post({path: '/posts', callback: controllers.posts.index}),
  someFn({path: '/posts/:post', callback: controllers.posts.show}),
];

// app.js
var { routes }    = require('./routes');
routes.forEach(route => route({app}));

回答by Radu Gheorghies

Let's say that you have a folder named "contollers".

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

In your app.js you can put this code:

在您的 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]");

... and ...

... 和 ...

router.get('/ping', controllers.ping.pinging);

in your controllers forlder you will have the file "ping.js" with this code:

在您的控制器文件夹中,您将拥有包含以下代码的文件“ping.js”:

exports.pinging = function(req, res, next){
    console.log("ping ...");
}

And this is it....

而这就是......

回答by Eldar Djafarov

For database separate out Data Access Service that will do all DB work with simple API and avoid shared state.

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

Separating routes.setup looks like overhead. I would prefer to place a configuration based routing instead. And configure routes in .json or with annotations.

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