จะรวมตัวจัดการเส้นทางในไฟล์หลายไฟล์ใน 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) ให้ความเห็นที่ดีกว่า: vimeo.com/56166857
avetisk

แก้ปัญหาการเราต์สำหรับหลายไฟล์ แต่ฟังก์ชั่นที่กำหนดใน app.js ไม่สามารถเข้าถึงได้ในเราต์
XIMRX

5
หากคุณต้องการฟังก์ชั่นบางอย่างเพียงแค่ใส่มันลงในโมดูล / ไฟล์อื่นและต้องการมันจากทั้ง app.js และ route.js
BFil

2
ฉันเข้าใจทุกอย่างที่ได้ยิน แต่ต้องการ ('./ เส้นทาง') (แอป) syntex นี้ทำให้ฉันคิดว่าใครจะบอกฉันได้ว่ามันคืออะไรหรือการใช้สิ่งนี้เท่าที่ฉันรู้ว่าแอพผ่านวัตถุ "แอพ"
ANINJa

6
มีคำตอบที่ดีกว่าสำหรับคำถามนี้ด้านล่าง - stackoverflow.com/a/37309212/297939
Dimitry

124

แม้ว่านี่จะเป็นคำถามที่เก่ากว่า แต่ฉันก็สะดุดที่นี่เพื่อหาทางแก้ไขปัญหาที่คล้ายกัน หลังจากลองใช้วิธีแก้ปัญหาบางอย่างที่นี่ฉันลงเอยด้วยการไปในทิศทางที่แตกต่างกันและคิดว่าฉันจะเพิ่มโซลูชันของฉันสำหรับคนอื่น ๆ ที่ลงเอยที่นี่

ใน express 4.x คุณจะได้รับอินสแตนซ์ของวัตถุเราเตอร์และนำเข้าไฟล์อื่นที่มีเส้นทางมากขึ้น คุณสามารถทำสิ่งนี้ซ้ำ ๆ เพื่อให้เส้นทางของคุณนำเข้าเส้นทางอื่น ๆ เพื่อให้คุณสร้างเส้นทางที่ง่ายต่อการบำรุงรักษา URL ตัวอย่างเช่นหากฉันมีไฟล์เส้นทางแยกต่างหากสำหรับจุดปลาย '/ การทดสอบ' ของฉันแล้วและต้องการเพิ่มชุดเส้นทางใหม่สำหรับ '/ การทดสอบ / อัตโนมัติ' ฉันอาจต้องการแยกเส้นทาง '/ อัตโนมัติ' เหล่านี้ออกเป็นไฟล์อื่นเพื่อ ทำให้ไฟล์ '/ ทดสอบ' ของฉันเล็กและง่ายต่อการจัดการ นอกจากนี้ยังช่วยให้คุณสามารถจัดกลุ่มเส้นทางที่มีเหตุผลร่วมกันโดยเส้นทาง 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
อันนี้เป็นคำตอบที่ดีที่สุดควรอยู่ด้านบนของรายการ! ขอบคุณ
Kostanos

ฉันจะใช้โครงสร้างนี้สำหรับ Node Js Rest API ได้อย่างไร
ชายรักชาย

@MSMurugan yep u สามารถสร้าง 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..
}

ทำซ้ำหลาย ๆ ครั้งตามที่ฉันต้องการจากนั้นในที่สุดก็ทำการวางแอพลิเคชั่น

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

1
ฉันชอบวิธีนี้ดีกว่าอนุญาตให้เพิ่มเส้นทางใหม่โดยไม่ต้องเพิ่มอะไรเฉพาะลงในไฟล์แอพหลัก
Jason Miesionczek

3
ดีฉันใช้วิธีนี้เช่นกันโดยมีการตรวจสอบเพิ่มเติมของนามสกุลไฟล์เนื่องจากฉันประสบปัญหาเกี่ยวกับไฟล์ swp
Geekfish

คุณไม่ต้องใช้ readdirSync ด้วยนี่ readdir ทำงานได้ดี
พอล

5
มีค่าใช้จ่ายในการใช้วิธีนี้ในการอ่านไฟล์ในไดเรกทอรีเทียบกับเพียงแค่ต้องมีเส้นทางในไฟล์ app.js ของคุณ?
Abadaba

ฉันต้องการทราบเช่นเดียวกันกับ @Abadaba สิ่งนี้จะได้รับการประเมินเมื่อคุณเปิดเซิร์ฟเวอร์หรือทุกคำขอ?
imns

19

และสร้างเพิ่มเติมจากคำตอบก่อนหน้ารุ่นเส้นทาง / 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

เส้นทาง recursive เต็มทุก.jsไฟล์ภายในโฟลเดอร์ใส่นี้ใน/routesapp.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

ฉันพยายามอัปเดตคำตอบนี้ด้วย "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

หากคุณใช้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");
});

ทำความสะอาดมากกว่าการใช้และvarmodule.exports


5

บิดหนึ่งคำตอบทั้งหมดเหล่านี้:

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

เพียงใช้ regex เพื่อกรองผ่านการทดสอบแต่ละไฟล์ในอาเรย์ มันไม่ได้เรียกซ้ำ แต่จะกรองโฟลเดอร์ที่ไม่ได้ลงท้ายด้วย. js


5

ฉันรู้ว่านี่เป็นคำถามเก่า แต่ฉันพยายามที่จะคิดออกบางอย่างเช่นสำหรับตัวเองและนี่คือสถานที่ที่ฉันจบลงดังนั้นฉันต้องการที่จะนำวิธีการแก้ปัญหาที่คล้ายกันในกรณีที่คนอื่นมีปัญหาเดียวกันฉัน ' เมตรมี มีโมดูลโหนดที่ดีออกมีเรียกว่าส่งมอบที่ทำสิ่งต่าง ๆ ของระบบไฟล์ที่เห็นที่นี่สำหรับคุณ (เช่น - ไม่มีสิ่ง 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/ …
Matt Browne

1
มันใช้งานได้สำหรับการแบ่งปันฟังก์ชั่นและตัวแปรทั่วโลกภายใต้ app.js? หรือคุณจะต้อง "ส่ง" สิ่งเหล่านี้เข้ามาwf.fooฯลฯ เนื่องจากไม่ได้อยู่ในขอบเขตเดียวกับโซลูชันที่นำเสนออื่น ๆ ฉันหมายถึงกรณีที่ปกติคุณจะเข้าถึงตัวแปร / ฟังก์ชั่นที่ใช้ร่วมกันใน wf.foo หากไม่ได้แยกออกจาก app.js
David

ใช่แล้วถ้าคุณประกาศฟังก์ชั่น 'foo' ใน app.js ดังนั้น app.get ('/ wf', foo); จะทำงาน
NiallJG


0

นี่อาจเป็นคำถาม / คำตอบสแต็คที่น่ากลัวที่สุดที่เคยมีมา ฉันชอบวิธีแก้ปัญหาของแซม / แบรดข้างต้น คิดว่าฉันจะคล้องจองกับเวอร์ชัน async ที่ฉันใช้งาน:

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 './routes'ดังนั้นฉันจะข้ามการตรวจสอบindex.jsเพราะฉันต้องการรวมที่หนึ่งเช่นกัน

แก้ไข: คุณสามารถใส่สิ่งนี้ในฟังก์ชั่นและเรียกมันซ้ำ (ฉันแก้ไขตัวอย่างเพื่อแสดงสิ่งนี้) หากคุณต้องการซ้อนเส้นทางของคุณในโฟลเดอร์ที่มีความลึกตามอำเภอใจ


2
ทำไมคุณต้องการรุ่น aysnc สันนิษฐานว่าคุณต้องการตั้งค่าเส้นทางทั้งหมดของคุณก่อนที่จะเริ่มให้บริการการจราจรหรืออื่น ๆ คุณอาจสิ้นสุดการส่ง 404s 'เท็จ'
โจเอบรัมส์

6
จริง ฉันเขียนมันในขณะที่ยังคงเรียนรู้โหนด ฉันเห็นด้วยในการหวนกลับว่ามันไม่สมเหตุสมผล
tandrewnichols

0

คุณสามารถใส่ฟังก์ชั่นเส้นทางทั้งหมดในไฟล์อื่น ๆ (โมดูล) และเชื่อมโยงไปยังไฟล์เซิร์ฟเวอร์หลัก ในไฟล์ 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}]
};   
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.