Bagaimana cara memasukkan penangan rute dalam banyak file dalam Express?

223

Dalam expressaplikasi NodeJS saya, saya memiliki app.jsbeberapa rute umum. Kemudian dalam sebuah wf.jsfile saya ingin mendefinisikan beberapa rute lagi.

Bagaimana saya bisa app.jsmengenali penangan rute lain yang ditentukan dalam wf.jsfile?

Sebuah sederhana membutuhkan tampaknya tidak bekerja.

rafidude
sumber
2
periksa jawaban ini stackoverflow.com/a/38718561/1153703
Bikesh M

Jawaban:

399

Jika Anda ingin meletakkan rute dalam file terpisah , misalnya routes.js, Anda dapat membuat routes.jsfile dengan cara ini:

module.exports = function(app){

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

    //other routes..
}

Dan kemudian Anda bisa meminta itu dari app.jsmelewatkan app objek dengan cara ini:

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

Lihat juga contoh-contoh ini

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

BFil
sumber
18
Sebenarnya, penulis (TJ Holowaychuck) memberikan persetujuan yang lebih baik: vimeo.com/56166857
avetisk
Memecahkan masalah perutean untuk banyak file, tetapi fungsi yang didefinisikan dalam app.js tidak dapat diakses di rute.
XIMRX
5
Jika Anda memerlukan beberapa fungsi, masukkan saja ke dalam modul / file lain dan minta dari kedua app.js dan routes.js
BFil
2
Saya mengerti semuanya mendengar tetapi membutuhkan ('./ rute') (aplikasi) sintaks ini membuat saya berpikir, adakah yang bisa mengatakan apa sebenarnya ini, atau apa gunanya ini sejauh yang saya tahu objek aplikasi yang lewat "app"
ANINJA
6
Ada jawaban yang lebih baik untuk pertanyaan ini di bawah - stackoverflow.com/a/37309212/297939
Dimitry
124

Meskipun ini pertanyaan yang lebih tua saya tersandung di sini mencari solusi untuk masalah serupa. Setelah mencoba beberapa solusi di sini saya akhirnya pergi ke arah yang berbeda dan berpikir saya akan menambahkan solusi saya untuk orang lain yang berakhir di sini.

Di express 4.x Anda bisa mendapatkan instance objek router dan mengimpor file lain yang berisi lebih banyak rute. Anda bahkan dapat melakukan ini secara rekursif sehingga rute Anda mengimpor rute lain yang memungkinkan Anda membuat jalur url yang mudah dikelola. Sebagai contoh jika saya sudah memiliki file rute terpisah untuk titik akhir '/ tes' saya dan ingin menambahkan set rute baru untuk '/ tes / otomatis' Saya mungkin ingin memecah rute '/ otomatis' ini ke file lain untuk simpan file '/ test' saya kecil dan mudah dikelola. Ini juga memungkinkan Anda mengelompokkan rute secara logis bersama dengan jalur URL yang benar-benar nyaman.

Isi dari ./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);

Isi ./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;

Isi dari ./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;
ShortRound1911
sumber
2
yang ini adalah jawaban terbaik, harus ada di daftar teratas! Terima kasih
Kostanos
dapatkah saya menggunakan struktur ini untuk Node Js Rest API?
MSM
@ MSMurugan Anda dapat membangun api sisa dengan pola ini.
ShortRound1911
@ ShortRound1911 Saya membangun api sisanya pola ini dan dimasukkan ke server hosting plesk, saya mendapatkan kesalahan
MSM
96

Membangun pada contoh @ShadowCloud, saya dapat secara dinamis memasukkan semua rute dalam sub direktori.

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

Kemudian menempatkan file rute di direktori rute seperti:

rute / test1.js

module.exports = function(app){

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

    //other routes..
}

Mengulangi sebanyak yang saya butuhkan dan akhirnya menempatkan app.js

require('./routes')(app);
Sam Corder
sumber
1
Saya suka pendekatan ini lebih baik, memungkinkan untuk menambahkan rute baru tanpa harus menambahkan sesuatu yang spesifik ke file aplikasi utama.
Jason Miesionczek
3
Bagus, saya menggunakan pendekatan ini juga, dengan pemeriksaan tambahan ekstensi file karena saya menghadapi masalah dengan file swp.
Geekfish
Anda juga tidak harus menggunakan readdirSync dengan ini, readdir berfungsi dengan baik.
Paul
5
Apakah ada overhead dalam menggunakan metode ini untuk membaca file dalam direktori vs hanya membutuhkan rute di file app.js Anda?
Abadaba
Saya juga ingin tahu sama dengan @Abadaba. Kapan ini dievaluasi, kapan Anda meluncurkan server atau pada setiap permintaan?
Imns
19

Dan membangun lebih banyak pada jawaban sebelumnya, versi rute / index.js ini akan mengabaikan semua file yang tidak diakhiri dengan .js (dan sendiri)

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);
    });
}
Brad Proctor
sumber
Terima kasih untuk ini. Saya memiliki seseorang di Mac yang menambahkan .DS_Storefile dan itu mengacaukan semuanya.
JayQuerie.com
19

Perutean rekursif penuh semua .jsfile di dalam /routesfolder, masukkan ini 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

di /routesAnda menempatkan whatevername.jsdan menginisialisasi rute Anda seperti ini:

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' });
    });
}
infinity1975
sumber
8

Saya mencoba memperbarui jawaban ini dengan "express": "^ 4.16.3". Jawaban ini mirip dengan 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;

Saya harap ini bisa membantu seseorang. Selamat coding!

Sukma Saputra
sumber
8

Jika Anda menggunakan express-4.x dengan TypeScript dan ES6, ini akan menjadi templat terbaik untuk digunakan:

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

Jauh lebih bersih daripada menggunakan vardan module.exports.

gihanchanuka
sumber
5

Satu tweak untuk semua jawaban ini:

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

Cukup gunakan regex untuk memfilter melalui pengujian setiap file dalam array. Ini tidak rekursif, tetapi akan menyaring folder yang tidak berakhir dengan .js

aliran menyesal
sumber
5

Saya tahu ini adalah pertanyaan lama, tetapi saya mencoba untuk mencari tahu sesuatu seperti untuk diri saya sendiri dan ini adalah tempat saya akhirnya, jadi saya ingin menempatkan solusi saya untuk masalah yang sama kalau-kalau ada orang lain yang memiliki masalah yang sama saya ' Saya memiliki. Ada modul simpul yang bagus di luar sana yang disebut konsinyasi yang melakukan banyak hal sistem file yang terlihat di sini untuk Anda (yaitu - tidak ada hal readdirSync). Sebagai contoh:

Saya memiliki aplikasi API yang saya coba untuk membangun dan saya ingin meletakkan semua permintaan yang pergi ke '/ api / *' untuk diautentikasi dan saya ingin menyimpan semua rute saya yang masuk ke direktori mereka sendiri (sebut saja 'api'). Di bagian utama aplikasi:

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

Di dalam direktori rute, saya memiliki direktori bernama "api" dan file bernama api.js. Di api.js, saya hanya punya:

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;

Semuanya bekerja seperti yang diharapkan. Semoga ini bisa membantu seseorang.

Mike S.
sumber
5

Jika Anda ingin file .js terpisah untuk mengatur rute Anda dengan lebih baik, cukup buat variabel di app.jsfile yang menunjuk ke lokasinya di sistem file:

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

kemudian,

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

di mana .foobeberapa fungsi dideklarasikan dalam wf.jsfile Anda . misalnya

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

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

}
NiallJG
sumber
1
+1. Ini adalah pendekatan yang ditunjukkan dalam contoh resmi di sini: github.com/strongloop/express/tree/master/examples/…
Matt Browne
1
Apakah ini berfungsi untuk berbagi fungsi dan variabel global di bawah app.js? Atau apakah Anda harus "meneruskan" mereka ke dalam wf.foo, dll. Karena mereka berada di luar ruang lingkup seperti solusi lain yang disajikan? Saya merujuk pada kasus di mana biasanya Anda akan mengakses variabel / fungsi bersama di wf.foo jika tidak dipisahkan dari app.js.
David
ya, jika Anda mendeklarasikan fungsi 'foo' di app.js kemudian app.get ('/ wf', foo); akan bekerja
NiallJG
0

Ini mungkin pertanyaan / jawaban (stack) overflow stack paling mengagumkan yang pernah ada. Saya suka solusi Sam / Brad di atas. Saya pikir saya akan berpadu dengan versi async yang saya terapkan:

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

Struktur direktori saya sedikit berbeda. Saya biasanya mendefinisikan rute di app.js (di direktori root proyek) dengan require-ing './routes'. Akibatnya, saya melewatkan cek index.jskarena saya ingin memasukkan yang juga.

EDIT: Anda juga dapat meletakkan ini dalam suatu fungsi dan menyebutnya secara rekursif (saya mengedit contoh untuk menunjukkan ini) jika Anda ingin membuat sarang rute Anda di folder dengan kedalaman sewenang-wenang.

tandrewnichols
sumber
2
Mengapa Anda menginginkan versi aysnc? Mungkin Anda ingin mengatur semua rute Anda sebelum mulai melayani lalu lintas atau Anda akhirnya bisa mengirim 404 'salah'.
Joe Abrams
6
Memang. Saya menulisnya sambil belajar simpul. Saya setuju dalam retrospeksi bahwa itu tidak masuk akal.
tandrewnichols
0

Anda dapat menempatkan semua fungsi rute di file lain (modul), dan menautkannya ke file server utama. di file kilat utama, tambahkan fungsi yang akan menautkan modul ke 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));
   }

dan panggil fungsi itu untuk setiap model rute:

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

dalam file modul (misalnya - file login.js), tentukan fungsinya seperti biasa:

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

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

dan mengekspornya dengan metode permintaan sebagai kunci dan nilainya adalah array objek, masing-masing dengan path dan tombol fungsi.

module.exports = {
   get: [{path:'/',func:login_screen}, {...} ],
   post: [{path:'/login:forgotPassword', func:forgot_password}]
};   
Tzvika Merchav
sumber