如何在 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.xTypeScript 和 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");
);

比使用varmodule.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 的多个文件中包含路由处理程序? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 node.js 在 html 中包含静态文件

如何使用 .Net 4.0 中包含的 HttpClient 类将文件上传到在 IIS Express 中运行的 Asp.Net MVC 4.0 操作

在 Visual Studio Express 2012 中包含路径

excel表格打开提示此工作簿中包含一个或多个无法更新的链接,应该怎么处理? 还有安全警告,怎么解决?

如何使用 jest 在 javascript 中测试 try catch 代码并在 express 中包含带有中间件的 next() 调用?

如何“运行”主包中包含多个文件的项目?