【发布时间】:2011-08-28 21:22:42
【问题描述】:
在我的 NodeJS express 应用程序中,我有 app.js,它有一些常见的路由。然后在wf.js 文件中,我想定义更多路线。
如何让app.js 识别wf.js 文件中定义的其他路由处理程序?
一个简单的 require 似乎不起作用。
【问题讨论】:
在我的 NodeJS express 应用程序中,我有 app.js,它有一些常见的路由。然后在wf.js 文件中,我想定义更多路线。
如何让app.js 识别wf.js 文件中定义的其他路由处理程序?
一个简单的 require 似乎不起作用。
【问题讨论】:
如果你想把路由放在一个单独的文件中,例如routes.js,你可以这样创建routes.js文件:
module.exports = function(app){
app.get('/login', function(req, res){
res.render('login', {
title: 'Express Login'
});
});
//other routes..
}
然后你可以从 app.js 要求它以这种方式传递 app 对象:
require('./routes')(app);
看看这些例子:https://github.com/visionmedia/express/tree/master/examples/route-separation
【讨论】:
require('./routes') 部分将导入在单独文件中创建的函数。 (app) 部分将以app 作为参数调用该函数。将函数导入为const routes = require('./routes'),然后调用为routes(app) 可能更容易理解。
在 Express 4.x 中,您可以获取路由器对象的实例并导入另一个包含更多路由的文件。您甚至可以递归地执行此操作,以便您的路由导入其他路由,从而让您创建易于维护的 URL 路径。
例如,如果我已经为 /tests 端点有一个单独的路由文件,并且想要为 /tests/automated 添加一组新路由,我可能想将这些 /automated 路由拆分到另一个文件中以保留我的/test 文件小且易于管理。它还可以让您通过 URL 路径在逻辑上将路由分组在一起,这非常方便。
./app.js的内容:
var express = require('express'),
app = express();
var testRoutes = require('./routes/tests');
// Import my test routes into the path '/test'
app.use('/tests', testRoutes);
./routes/tests.js的内容:
var express = require('express'),
router = express.Router();
var automatedRoutes = require('./testRoutes/automated');
router
// Add a binding to handle '/tests'
.get('/', function(){
// render the /tests view
})
// Import my automated routes into the path '/tests/automated'
// This works because we're already within the '/tests' route
// so we're simply appending more routes to the '/tests' endpoint
.use('/automated', automatedRoutes);
module.exports = router;
./routes/testRoutes/automated.js的内容:
var express = require('express'),
router = express.Router();
router
// Add a binding for '/tests/automated/'
.get('/', function(){
// render the /tests/automated view
})
module.exports = router;
【讨论】:
以@ShadowCloud 的示例为基础,我能够在子目录中动态包含所有路由。
routes/index.js
var fs = require('fs');
module.exports = function(app){
fs.readdirSync(__dirname).forEach(function(file) {
if (file == "index.js") return;
var name = file.substr(0, file.indexOf('.'));
require('./' + name)(app);
});
}
然后像这样将路由文件放在路由目录中:
routes/test1.js
module.exports = function(app){
app.get('/test1/', function(req, res){
//...
});
//other routes..
}
根据需要重复多次,最后在 app.js 中放置
require('./routes')(app);
【讨论】:
在上一个答案的基础上进一步构建,此版本的 routes/index.js 将忽略任何不以 .js 结尾的文件(及其本身)
var fs = require('fs');
module.exports = function(app) {
fs.readdirSync(__dirname).forEach(function(file) {
if (file === "index.js" || file.substr(file.lastIndexOf('.') + 1) !== 'js')
return;
var name = file.substr(0, file.indexOf('.'));
require('./' + name)(app);
});
}
【讨论】:
.DS_Store 文件,结果搞砸了。
完整递归路由/routes文件夹内的所有.js文件,把它放在app.js中。
// Initialize ALL routes including subfolders
var fs = require('fs');
var path = require('path');
function recursiveRoutes(folderName) {
fs.readdirSync(folderName).forEach(function(file) {
var fullName = path.join(folderName, file);
var stat = fs.lstatSync(fullName);
if (stat.isDirectory()) {
recursiveRoutes(fullName);
} else if (file.toLowerCase().indexOf('.js')) {
require('./' + fullName)(app);
console.log("require('" + fullName + "')");
}
});
}
recursiveRoutes('routes'); // Initialize it
在/routes 中输入whatevername.js 并像这样初始化您的路线:
module.exports = function(app) {
app.get('/', function(req, res) {
res.render('index', { title: 'index' });
});
app.get('/contactus', function(req, res) {
res.render('contactus', { title: 'contactus' });
});
}
【讨论】:
'./',因为您使用的是路径。所以只需 require(fullName)(app); 和 (2) 你需要在开头添加这个 if (file === 'index.js') return false; 否则函数将无限期调用。
如果您将 express-4.x 与 TypeScript 和 ES6 一起使用,这将是最好的模板:
src/api/login.ts
import express, { Router, Request, Response } from "express";
const router: Router = express.Router();
// POST /user/signin
router.post('/signin', async (req: Request, res: Response) => {
try {
res.send('OK');
} catch (e) {
res.status(500).send(e.toString());
}
});
export default router;
src/app.ts
import express, { Request, Response } from "express";
import compression from "compression"; // compresses requests
import expressValidator from "express-validator";
import bodyParser from "body-parser";
import login from './api/login';
const app = express();
app.use(compression());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(expressValidator());
app.get('/public/hc', (req: Request, res: Response) => {
res.send('OK');
});
app.use('/user', login);
app.listen(8080, () => {
console.log("Press CTRL-C to stop\n");
});
比使用var 和module.exports 干净得多。
【讨论】:
我正在尝试使用"express": "^4.16.3" 更新此答案。这个答案类似于 ShortRound1911 中的答案。
server.js:
const express = require('express');
const mongoose = require('mongoose');
const bodyParser = require('body-parser');
const db = require('./src/config/db');
const routes = require('./src/routes');
const port = 3001;
const app = new express();
//...use body-parser
app.use(bodyParser.urlencoded({ extended: true }));
//...fire connection
mongoose.connect(db.url, (err, database) => {
if (err) return console.log(err);
//...fire the routes
app.use('/', routes);
app.listen(port, () => {
console.log('we are live on ' + port);
});
});
/src/routes/index.js:
const express = require('express');
const app = express();
const siswaRoute = require('./siswa_route');
app.get('/', (req, res) => {
res.json({item: 'Welcome ini separated page...'});
})
.use('/siswa', siswaRoute);
module.exports = app;
/src/routes/siswa_route.js:
const express = require('express');
const app = express();
app.get('/', (req, res) => {
res.json({item: 'Siswa page...'});
});
module.exports = app;
【讨论】:
如果您想要一个单独的 .js 文件来更好地组织您的路线,只需在 app.js 文件中创建一个变量,指向其在文件系统中的位置:
var wf = require(./routes/wf);
那么,
app.get('/wf', wf.foo );
其中.foo 是在您的wf.js 文件中声明的某个函数。例如
// wf.js file
exports.foo = function(req,res){
console.log(` request object is ${req}, response object is ${res} `);
}
【讨论】:
wf.foo 等,因为它们与其他提出的解决方案一样超出范围?我指的是通常你会访问 wf.foo 中的共享变量/函数的情况,如果它没有从 app.js 中分离出来。
对所有这些答案进行一次调整:
var routes = fs.readdirSync('routes')
.filter(function(v){
return (/.js$/).test(v);
});
只需使用正则表达式通过测试数组中的每个文件进行过滤。不是递归的,但是会过滤掉不以.js结尾的文件夹
【讨论】:
我知道这是一个老问题,但我试图为自己找出类似的东西,这就是我最终找到的地方,所以我想把我的解决方案放在类似的问题上,以防其他人有同样的问题我遇到的问题。有一个很好的节点模块,叫做consign,它为你做了很多在这里看到的文件系统的东西(即 - 没有 readdirSync 的东西)。例如:
我有一个正在尝试构建的 RESTful API 应用程序,我想将所有转到“/api/*”的请求都进行身份验证,并且我想将所有进入 api 的路由存储到他们自己的目录(让我们称之为'api')。在应用程序的主要部分:
app.use('/api', [authenticationMiddlewareFunction], require('./routes/api'));
在 routes 目录中,我有一个名为“api”的目录和一个名为 api.js 的文件。在 api.js 中,我只有:
var express = require('express');
var router = express.Router();
var consign = require('consign');
// get all routes inside the api directory and attach them to the api router
// all of these routes should be behind authorization
consign({cwd: 'routes'})
.include('api')
.into(router);
module.exports = router;
一切都按预期进行。希望这对某人有所帮助。
【讨论】:
【讨论】:
index.js
const express = require("express");
const app = express();
const http = require('http');
const server = http.createServer(app).listen(3000);
const router = (global.router = (express.Router()));
app.use('/books', require('./routes/books'))
app.use('/users', require('./routes/users'))
app.use(router);
路由/users.js
const router = global.router
router.get('/', (req, res) => {
res.jsonp({name: 'John Smith'})
}
module.exports = router
routes/books.js
const router = global.router
router.get('/', (req, res) => {
res.jsonp({name: 'Dreams from My Father by Barack Obama'})
}
module.exports = router
如果您的服务器在本地运行 (http://localhost:3000),那么
// Users
curl --request GET 'localhost:3000/users' => {name: 'John Smith'}
// Books
curl --request GET 'localhost:3000/books' => {name: 'Dreams from My Father by Barack Obama'}
【讨论】:
这可能是有史以来最棒的堆栈溢出问题/答案。我喜欢上面山姆/布拉德的解决方案。以为我会加入我实现的异步版本:
function loadRoutes(folder){
if (!folder){
folder = __dirname + '/routes/';
}
fs.readdir(folder, function(err, files){
var l = files.length;
for (var i = 0; i < l; i++){
var file = files[i];
fs.stat(file, function(err, stat){
if (stat && stat.isDirectory()){
loadRoutes(folder + '/' + file + '/');
} else {
var dot = file.lastIndexOf('.');
if (file.substr(dot + 1) === 'js'){
var name = file.substr(0, dot);
// I'm also passing argv here (from optimist)
// so that I can easily enable debugging for all
// routes.
require(folder + name)(app, argv);
}
}
});
}
});
}
我的目录结构有点不同。我通常通过require-ing './routes' 在 app.js(在项目的根目录中)定义路由。因此,我跳过了对 index.js 的检查,因为我想也包括那个检查。
编辑: 如果你想将你的路由嵌套在任意深度的文件夹中,你也可以把它放在一个函数中并递归调用它(我编辑了这个例子来展示这个)。
【讨论】:
您可以将所有路由功能放在其他文件(模块)中,并将其链接到主服务器文件。 在主 express 文件中,添加一个将模块链接到服务器的函数:
function link_routes(app, route_collection){
route_collection['get'].forEach(route => app.get(route.path, route.func));
route_collection['post'].forEach(route => app.post(route.path, route.func));
route_collection['delete'].forEach(route => app.delete(route.path, route.func));
route_collection['put'].forEach(route => app.put(route.path, route.func));
}
并为每个路由模型调用该函数:
link_routes(app, require('./login.js'))
在模块文件中(例如 - login.js 文件),像往常一样定义函数:
const login_screen = (req, res) => {
res.sendFile(`${__dirname}/pages/login.html`);
};
const forgot_password = (req, res) => {
console.log('we will reset the password here')
}
并以请求方法作为键导出它,值是一个对象数组,每个对象都有路径和功能键。
module.exports = {
get: [{path:'/',func:login_screen}, {...} ],
post: [{path:'/login:forgotPassword', func:forgot_password}]
};
【讨论】: