如何在 Express 的多个文件中包含路由处理程序? [复制]
Posted
技术标签:
【中文标题】如何在 Express 的多个文件中包含路由处理程序? [复制]【英文标题】:How to include route handlers in multiple files in Express? [duplicate] 【发布时间】:2011-08-28 21:22:42 【问题描述】:在我的 NodeJS express
应用程序中,我有 app.js
,它有一些常见的路由。然后在wf.js
文件中,我想定义更多路线。
如何让app.js
识别wf.js
文件中定义的其他路由处理程序?
一个简单的 require 似乎不起作用。
【问题讨论】:
查看这个答案***.com/a/38718561/1153703 【参考方案1】:如果你想把路由放在一个单独的文件中,例如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
【讨论】:
其实作者(TJ Holowaychuck)给出了一个更好的方法:vimeo.com/56166857 如果您需要一些功能,只需将它们放入另一个模块/文件中,并从 app.js 和 routes.js 中都需要它 我听懂了一切,但 require('./routes')(app) 这个语法让我大吃一惊,谁能告诉我这到底是什么,或者这个有什么用处知道它传递的应用对象“app” 下面这个问题有更好的答案——***.com/a/37309212/297939 @RishabhAgrawal 它看起来比实际复杂。require('./routes')
部分将导入在单独文件中创建的函数。 (app)
部分将以app
作为参数调用该函数。将函数导入为const routes = require('./routes')
,然后调用为routes(app)
可能更容易理解。【参考方案2】:
在 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;
【讨论】:
这个是最好的答案,应该排在首位!谢谢 我可以将这个结构用于 Node Js Rest API 吗? @M.S.Murugan 是的,你可以用这种模式构建一个 rest api。 @ShortRound1911 我正在构建一个rest api这个模式并放到plesk托管服务器上,我收到一个错误 这个答案应该是最好的【参考方案3】:以@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);
【讨论】:
我更喜欢这种方法,允许添加新路线而无需添加任何特定于主应用程序文件的内容。 很好,我也使用这种方法,另外检查文件扩展名,因为我遇到了 swp 文件的问题。 您也不必使用带有此功能的 readdirSync,readdir 工作正常。 使用此方法读取目录中的文件与仅需要 app.js 文件中的路由相比是否有任何开销? 我也想知道和@Abadaba一样。何时评估,何时启动服务器或在每个请求上?【参考方案4】:在上一个答案的基础上进一步构建,此版本的 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);
);
【讨论】:
谢谢。我有人在 Mac 上添加了.DS_Store
文件,结果搞砸了。【参考方案5】:
完整递归路由/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' );
);
【讨论】:
感谢您的精彩回答。帮了我很多。实施时,我意识到(1)您在需要时不需要'./'
,因为您使用的是路径。所以只需 require(fullName)(app);
和 (2) 你需要在开头添加这个 if (file === 'index.js') return false;
否则函数将无限期调用。【参考方案6】:
如果您将 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
干净得多。
【讨论】:
这是我在 2022 年最终使用的答案,谢谢!【参考方案7】:我正在尝试使用"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;
【讨论】:
【参考方案8】:如果您想要一个单独的 .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 `);
【讨论】:
+1。这是官方示例中显示的方法:github.com/strongloop/express/tree/master/examples/… 这对于在 app.js 下共享全局函数和变量有用吗?或者您是否必须将它们“传递”到wf.foo
等,因为它们与其他提出的解决方案一样超出范围?我指的是通常你会访问 wf.foo 中的共享变量/函数的情况,如果它没有从 app.js 中分离出来。
是的,如果你在 app.js 中声明了 'foo' 函数,那么 app.get('/wf', foo);会工作【参考方案9】:
对所有这些答案进行一次调整:
var routes = fs.readdirSync('routes')
.filter(function(v)
return (/.js$/).test(v);
);
只需使用正则表达式通过测试数组中的每个文件进行过滤。不是递归的,但是会过滤掉不以.js结尾的文件夹
【讨论】:
【参考方案10】:我知道这是一个老问题,但我试图为自己找出类似的东西,这就是我最终找到的地方,所以我想把我的解决方案放在类似的问题上,以防其他人有同样的问题我遇到的问题。有一个很好的节点模块,叫做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;
一切都按预期进行。希望这对某人有所帮助。
【讨论】:
【参考方案11】:我为此编写了一个小插件!厌倦了一遍又一遍地编写相同的代码。
https://www.npmjs.com/package/js-file-req
希望对你有帮助。
【讨论】:
【参考方案12】: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'
【讨论】:
【参考方案13】:这可能是有史以来最棒的堆栈溢出问题/答案。我喜欢上面山姆/布拉德的解决方案。以为我会加入我实现的异步版本:
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
的检查,因为我想也包括那个检查。
编辑: 如果你想将你的路由嵌套在任意深度的文件夹中,你也可以把它放在一个函数中并递归调用它(我编辑了这个例子来展示这个)。
【讨论】:
您为什么想要 aysnc 版本?大概您想在开始提供流量之前设置所有路线,否则您最终可能会发送一些“错误”404。 确实如此。我在学习节点时写了它。回想起来,我同意这没有意义。【参考方案14】:您可以将所有路由功能放在其他文件(模块)中,并将其链接到主服务器文件。 在主 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]
;
【讨论】:
以上是关于如何在 Express 的多个文件中包含路由处理程序? [复制]的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 .Net 4.0 中包含的 HttpClient 类将文件上传到在 IIS Express 中运行的 Asp.Net MVC 4.0 操作
在 Visual Studio Express 2012 中包含路径
excel表格打开提示此工作簿中包含一个或多个无法更新的链接,应该怎么处理? 还有安全警告,怎么解决?
如何使用 jest 在 javascript 中测试 try catch 代码并在 express 中包含带有中间件的 next() 调用?