Node.js Express:如何将应用程序实例传递到来自不同文件的路由?
我想将我的路由拆分为不同的文件,其中一个文件包含所有路由,另一个文件包含相应的操作。我目前有一个解决方案来实现这一点,但是我需要使应用程序实例成为全局的,以便能够在操作中访问它。 我当前的设置如下所示: app.js: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(
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();
});
//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
函数之外,比如: