Come includere i gestori di route in più file in Express?


223

Nella mia expressapplicazione NodeJS ho app.jsalcuni percorsi comuni. Quindi in un wf.jsfile vorrei definire alcune altre rotte.

Come posso app.jsriconoscere altri gestori di percorso definiti nel wf.jsfile?

Un semplice requisito non sembra funzionare.


2
controllare questa risposta stackoverflow.com/a/38718561/1153703
Bikesh M

Risposte:


399

Se si desidera inserire i percorsi in un file separato , ad esempio routes.js, è possibile creare il routes.jsfile in questo modo:

module.exports = function(app){

    app.get('/login', function(req, res){
        res.render('login', {
            title: 'Express Login'
        });
    });

    //other routes..
}

E quindi puoi richiederlo per app.jspassare l' app oggetto in questo modo:

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

Dai un'occhiata anche a questi esempi

https://github.com/visionmedia/express/tree/master/examples/route-separation


18
In realtà, l'autore (TJ Holowaychuck) dà una migliore approvazione: vimeo.com/56166857
avetisk il

Risolve il problema di routing per più file, ma le funzioni definite in app.js non sono accessibili nelle route.
XIMRX,

5
Se hai bisogno di alcune funzioni, inseriscile in un altro modulo / file e richiedilo sia da app.js che route.js
BFil

2
Ho capito tutto sentire ma richiedere ('./ rotte') (app) questa sintassi mi fa saltare la testa, qualcuno può dirmi che cosa è esattamente questo, o a cosa serve questo per quanto ne so il suo oggetto di passaggio "app"
ANinJa,

6
C'è una risposta migliore a questa domanda qui sotto - stackoverflow.com/a/37309212/297939
Dimitry

124

Anche se questa è una domanda più vecchia, mi sono imbattuto qui alla ricerca di una soluzione a un problema simile. Dopo aver provato alcune delle soluzioni qui ho finito per andare in una direzione diversa e ho pensato di aggiungere la mia soluzione per chiunque finisca qui.

In Express 4.x è possibile ottenere un'istanza dell'oggetto router e importare un altro file che contiene più route. Puoi anche farlo in modo ricorsivo in modo che i tuoi percorsi importino altri percorsi permettendoti di creare percorsi URL facili da mantenere. Ad esempio, se ho già un file di route separato per il mio endpoint "/ test" e desidero aggiungere un nuovo set di route per "/ test / automatizzato", potrei voler suddividere queste route "/ automatizzate" in un altro file per mantieni il mio file '/ test' piccolo e facile da gestire. Ti consente inoltre di raggruppare logicamente i percorsi in base al percorso dell'URL che può essere davvero conveniente.

Contenuti di ./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);

Contenuto di ./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;

Contenuti di ./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
questa è la risposta migliore, dovrebbe essere in cima alla lista! Grazie
Kostanos il

posso usare questa struttura per Node Js Rest API?
MSM

@MSMurugan, sì, puoi costruire un'api di riposo con questo schema.
ShortRound1911,

@ ShortRound1911 Sto costruendo un resto dopo questo schema e lo metto sul server di hosting Plesk, ricevo un errore
MSM

96

Basandomi sull'esempio di @ShadowCloud sono stato in grado di includere dinamicamente tutti i percorsi in una sottodirectory.

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

Quindi posizionando i file di route nella directory route in questo modo:

Percorsi / test1.js

module.exports = function(app){

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

    //other routes..
}

Ripetendolo per tutte le volte che mi serviva e infine inserendo app.js

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

1
mi piace meglio questo approccio, consente di aggiungere nuovi percorsi senza dover aggiungere nulla di specifico al file dell'app principale.
Jason Miesionczek,

3
Bene, utilizzo anche questo approccio, con un controllo aggiuntivo dell'estensione del file poiché ho riscontrato problemi con i file swp.
Geekfish,

Inoltre, non è necessario utilizzare readdirSync con questo, readdir funziona bene.
Paul,

5
Esiste un sovraccarico nell'uso di questo metodo per leggere i file nella directory anziché richiedere i percorsi nel file app.js?
Abadaba,

Mi piacerebbe anche sapere lo stesso di @Abadaba. Quando viene valutato, quando si avvia il server o su ogni richiesta?
ims

19

E costruisci ancora di più sulla risposta precedente, questa versione di route / index.js ignorerà tutti i file che non finiscono in .js (e se stesso)

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

Grazie per questo. Avevo qualcuno su un Mac che aggiungeva .DS_Storefile e stava rovinando tutto.
JayQuerie.com,

19

Instradamento completo ricorsivo di tutti i .jsfile all'interno della /routescartella, inseriscilo 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

nel /routesmettere whatevername.jse inizializzare i percorsi in questo modo:

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

Sto cercando di aggiornare questa risposta con "express": "^ 4.16.3". Questa risposta è simile a 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;

Spero che questo possa aiutare qualcuno. Buona programmazione!


8

Se stai usando express-4.x con TypeScript ed ES6, questo sarebbe il modello migliore da usare:

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

Molto più pulito dell'uso di vare module.exports.


5

Una modifica a tutte queste risposte:

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

Basta usare una regex per filtrare testando ogni file nell'array. Non è ricorsivo, ma filtrerà le cartelle che non finiscono in .js


5

So che questa è una vecchia domanda, ma stavo cercando di capire qualcosa di simile a me stesso e questo è il posto in cui sono finito, quindi volevo mettere la mia soluzione a un problema simile nel caso in cui qualcun altro abbia gli stessi problemi che ho " sto avendo. C'è un bel modulo nodo là fuori chiamato consign che fa molte cose del file system che è visto qui per te (cioè - nessuna roba readdirSync). Per esempio:

Ho un'applicazione API riposante che sto cercando di compilare e voglio mettere tutte le richieste che vanno a '/ api / *' per essere autenticate e voglio archiviare tutti i miei percorsi che vanno in api nella propria directory (chiamiamolo semplicemente 'api'). Nella parte principale dell'app:

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

All'interno della directory dei percorsi, ho una directory chiamata "api" e un file chiamato api.js. In api.js, ho semplicemente:

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;

Tutto ha funzionato come previsto. Spero che questo aiuti qualcuno.


5

Se vuoi un file .js separato per organizzare meglio i tuoi percorsi, crea una variabile nel app.jsfile che punta alla sua posizione nel filesystem:

var wf = require(./routes/wf);

poi,

app.get('/wf', wf.foo );

dove .fooè dichiarata una funzione nel tuo wf.jsfile. per esempio

// wf.js file 
exports.foo = function(req,res){

          console.log(` request object is ${req}, response object is ${res} `);

}

1
+1. Questo è l'approccio mostrato nell'esempio ufficiale qui: github.com/strongloop/express/tree/master/examples/…
Matt Browne,

1
Funziona con la condivisione di funzioni e variabili globali in app.js? O dovresti "passarli" dentro wf.foo, ecc. Dato che sono fuori campo come con le altre soluzioni presentate? Mi riferisco al caso in cui normalmente accederesti a variabili / funzioni condivise in wf.foo se non fosse separato da app.js.
David

sì, se si dichiara la funzione 'pippo' in app.js quindi app.get ('/ wf', pippo); funzionerà
NiallJG il


0

Questa è probabilmente la domanda / risposta (e) di overflow dello stack più fantastica di sempre. Io amo le soluzioni di Sam / Brad sopra. Ho pensato di entrare in contatto con la versione asincrona che ho implementato:

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

La mia struttura di directory è leggermente diversa. In genere definisco i percorsi in app.js (nella directory principale del progetto) require-ing './routes'. Di conseguenza, sto saltando l'assegno index.jsperché voglio includere anche quello.

EDIT: puoi anche mettere questo in una funzione e chiamarlo ricorsivamente (ho modificato l'esempio per mostrarlo) se vuoi annidare i tuoi percorsi in cartelle di profondità arbitraria.


2
Perché vorresti una versione aysnc? Presumibilmente vuoi impostare tutti i tuoi percorsi prima di iniziare a servire il traffico, altrimenti potresti finire per inviare alcuni 404 "falsi".
Joe Abrams,

6
Infatti. L'ho scritto mentre imparavo ancora il nodo. Concordo con il senno di poi che non ha senso.
Tandrewnichols,

0

puoi inserire tutte le funzioni del percorso in altri file (moduli) e collegarlo al file del server principale. nel file espresso principale, aggiungi una funzione che collegherà il modulo al server:

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

e chiama quella funzione per ciascun modello di percorso:

link_routes(app, require('./login.js'))

nei file del modulo (ad esempio il file login.js), definire le funzioni come al solito:

const login_screen = (req, res) => {
    res.sendFile(`${__dirname}/pages/login.html`);
};

const forgot_password = (req, res) => {
    console.log('we will reset the password here')
}

ed esportarlo con il metodo di richiesta come chiave e il valore è un array di oggetti, ognuno con i tasti path e funzione.

module.exports = {
   get: [{path:'/',func:login_screen}, {...} ],
   post: [{path:'/login:forgotPassword', func:forgot_password}]
};   
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.