Как включить обработчики маршрутов в несколько файлов в Express?


223

В моем expressприложении NodeJS app.jsесть несколько общих маршрутов. Затем в wf.jsфайле я хотел бы определить еще несколько маршрутов.

Как я могу app.jsузнать другие обработчики маршрута, определенные в wf.jsфайле?

Простое требование , похоже, не работает.


2
проверить этот ответ stackoverflow.com/a/38718561/1153703
Bikesh M

Ответы:


399

Например , если вы хотите поместить маршруты в отдельный файл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


18
На самом деле, автор (TJ Holowaychuck) дает лучшее approche: vimeo.com/56166857
avetisk

Решает проблему маршрутизации для нескольких файлов, но функции, определенные в app.js, недоступны в маршрутах.
XIMRX

5
Если вам нужны некоторые функции, просто поместите их в другой модуль / файл и потребуйте их как из app.js, так и route.js
BFil

2
Я понял, что все слышат, но требуют ('./ маршруты') (приложение), этот синтаксис поражает меня, кто-нибудь может сказать мне, что это именно, или как это использовать, насколько я знаю, его прохождение объекта приложения "приложение"
ANinJa

6
Вот лучший ответ на этот вопрос ниже - stackoverflow.com/a/37309212/297939
Дмитрий

124

Несмотря на то, что это старый вопрос, я наткнулся здесь на поиски решения аналогичной проблемы. Попробовав некоторые решения здесь, я в конечном итоге пошел в другом направлении и подумал, что добавлю свое решение для всех, кто окажется здесь.

В Express 4.x вы можете получить экземпляр объекта маршрутизатора и импортировать другой файл, который содержит больше маршрутов. Вы даже можете сделать это рекурсивно, чтобы ваши маршруты импортировали другие маршруты, позволяя вам создавать простые для поддержки URL-пути. Например, если у меня уже есть отдельный файл маршрута для моей конечной точки «/ tests», и я хочу добавить новый набор маршрутов для «/ tests / automatic», я могу разбить эти «/ автоматизированные» маршруты на другой файл для сохранить мой файл / 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 '/test'
  .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;

2
это лучший ответ, должен быть в начале списка! Спасибо
Костанос

я могу использовать эту структуру для Node Js Rest API?
МСМ

@MSMurugan Да, вы можете построить остальные API с помощью этого шаблона.
ShortRound1911

@ ShortRound1911 Я строю остальные API этого шаблона и помещаю их на хост-сервер plesk, я получаю сообщение об ошибке
MSM

96

Основываясь на примере @ShadowCloud, я смог динамически включить все маршруты в подкаталог.

маршруты / 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);
    });
}

Затем поместите файлы маршрутов в каталог маршрутов следующим образом:

маршруты / test1.js

module.exports = function(app){

    app.get('/test1/', function(req, res){
        //...
    });

    //other routes..
}

Повторяя , что столько раз , сколько мне нужно , а затем , наконец , в app.js размещения

require('./routes')(app);

1
мне больше нравится этот подход, он позволяет добавлять новые маршруты без необходимости добавлять что-либо специфичное для основного файла приложения.
Джейсон Месьончек,

3
Хорошо, я также использую этот подход с дополнительной проверкой расширения файла, так как я столкнулся с проблемами с файлами swp.
Geekfish

Вы также не должны использовать readdirSync с этим, readdir работает отлично.
Пол

5
Существуют ли какие-либо издержки при использовании этого метода для чтения файлов в каталоге по сравнению с просто необходимыми маршрутами в вашем файле app.js?
Абадаба

Я также хотел бы знать то же самое, что и @Abadaba. Когда это оценивается, когда вы запускаете сервер или при каждом запросе?
imns

19

Более того, опираясь на предыдущий ответ, эта версия route / 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файлы, и это все испортило.
JayQuerie.com

19

Полная рекурсивная маршрутизация всех .jsфайлов внутри /routesпапки, вставьте это 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' });
    });
}

8

Я пытаюсь обновить этот ответ с помощью «экспресс»: «^ 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

Если вы используете 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.


5

Один твик ко всем этим ответам:

var routes = fs.readdirSync('routes')
      .filter(function(v){
         return (/.js$/).test(v);
      });

Просто используйте регулярное выражение для фильтрации путем тестирования каждого файла в массиве. Это не рекурсивно, но оно отфильтровывает папки, которые не заканчиваются на .js


5

Я знаю, что это старый вопрос, но я пытался придумать что-то подобное для себя, и это то место, в котором я оказался, поэтому я хотел найти решение аналогичной проблемы на случай, если у кого-то еще возникнут те же проблемы, что и у меня ». Я имею. Есть замечательный модуль узла, называемый consign, который делает много вещей из файловой системы, которые мы здесь видим (т. Е. Никаких вещей readdirSync). Например:

У меня есть спокойное API-приложение, которое я пытаюсь создать, и я хочу поместить все запросы, которые идут в '/ api / *', для аутентификации, и я хочу сохранить все свои маршруты, которые идут в api, в их собственный каталог (давайте просто назовем это «API»). В основной части приложения:

app.use('/api', [authenticationMiddlewareFunction], require('./routes/api'));

Внутри каталога маршрутов у меня есть каталог с именем "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;

Все заработало как положено. Надеюсь, это кому-нибудь поможет.


5

Если вы хотите, чтобы отдельный файл .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
+1. Этот подход показан в официальном примере здесь: github.com/strongloop/express/tree/master/examples/…
Мэтт Браун

1
Это работает для совместного использования глобальных функций и переменных в app.js? Или вам придется «передать» их wf.fooи т. Д., Поскольку они выходят за рамки, как и в других представленных решениях? Я имею в виду случай, когда обычно вы получаете доступ к общим переменным / функциям в wf.foo, если они не отделены от app.js.
Дэвид

да, если вы объявите функцию 'foo' в app.js, тогда app.get ('/ wf', foo); будет работать
NiallJG


0

Это, возможно, самый крутой вопрос / ответ (ы) о переполнении стека за всю историю. Я люблю решения Сэма / Брэда выше. Думал, что я буду взаимодействовать с асинхронной версией, которую я реализовал:

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

Моя структура каталогов немного отличается. Обычно я определяю маршруты в app.js (в корневом каталоге проекта) с помощью require-ing './routes'. Следовательно, я пропускаю проверку, index.jsпотому что хочу включить и эту.

РЕДАКТИРОВАТЬ: Вы также можете поместить это в функцию и вызывать ее рекурсивно (я отредактировал пример, чтобы показать это), если вы хотите вложить ваши маршруты в папки произвольной глубины.


2
Зачем вам нужна версия aysnc? Предположительно, вы хотите настроить все свои маршруты перед тем, как начать обслуживать трафик, иначе вы могли бы в конечном итоге отправить «ложные» 404.
Джо Абрамс

6
На самом деле. Я написал это, пока еще изучал узел. Оглядываясь назад, я согласен, что это не имеет смысла.
тандрюхиолы

0

Вы можете поместить все функции маршрута в другие файлы (модули) и связать их с файлом основного сервера. в главном экспресс-файле добавьте функцию, которая свяжет модуль с сервером:

   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}]
};   
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.