Làm cách nào để bao gồm các trình xử lý tuyến đường trong nhiều tệp trong Express?


223

Trong expressứng dụng NodeJS của tôi, tôi có app.jsmột vài tuyến phổ biến. Sau đó, trong một wf.jstập tin tôi muốn xác định thêm một vài tuyến đường.

Làm cách nào tôi có app.jsthể nhận ra các trình xử lý tuyến đường khác được xác định trong wf.jstệp?

Một yêu cầu đơn giản dường như không hoạt động.


2
kiểm tra câu trả lời này stackoverflow.com/a/38718561/1153703
Bikesh M

Câu trả lời:


399

Ví dụ: nếu bạn muốn đặt các tuyến đường trong một tệp riêng biệtroutes.js , bạn có thể tạo routes.jstệp theo cách này:

module.exports = function(app){

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

    //other routes..
}

Và sau đó bạn có thể yêu cầu nó app.jstruyền app đối tượng theo cách này:

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

Cũng đã xem xét các ví dụ này

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


18
Trên thực tế, tác giả (TJ Holowaychuck) đưa ra một phê duyệt tốt hơn: vimeo.com/56166857
avetisk

Giải quyết vấn đề định tuyến cho nhiều tệp, nhưng các hàm được xác định trong app.js không thể truy cập được trong các tuyến.
XIMRX

5
Nếu bạn cần một số chức năng, chỉ cần đặt chúng vào một mô-đun / tệp khác và yêu cầu nó từ cả app.js và Rout.js
BFil

2
Tôi hiểu tất cả mọi thứ nghe được nhưng yêu cầu ('./ tuyến') (ứng dụng) cú pháp này thổi vào tâm trí tôi, bất kỳ ai cũng có thể cho tôi biết chính xác đây là gì, hoặc việc sử dụng này là gì khi tôi biết đối tượng ứng dụng đi qua của nó "ứng dụng"
ANinJa

6
Có một câu trả lời tốt hơn cho câu hỏi này dưới đây - stackoverflow.com/a/37309212/297939
Dimitry

124

Mặc dù đây là một câu hỏi cũ hơn, tôi tình cờ tìm thấy một giải pháp cho một vấn đề tương tự. Sau khi thử một số giải pháp ở đây, cuối cùng tôi đã đi theo một hướng khác và nghĩ rằng tôi sẽ thêm giải pháp của mình cho bất kỳ ai khác kết thúc ở đây.

Trong express 4.x, bạn có thể lấy một thể hiện của đối tượng bộ định tuyến và nhập một tệp khác có chứa nhiều tuyến đường hơn. Bạn thậm chí có thể làm điều này một cách đệ quy để các tuyến của bạn nhập các tuyến khác cho phép bạn tạo các đường dẫn url dễ dàng để duy trì. Ví dụ: nếu tôi đã có tệp tuyến đường riêng cho điểm cuối '/ tests' của mình và muốn thêm một bộ tuyến đường mới cho '/ tests / tự động' Tôi có thể muốn chia các tuyến đường '/ tự động' này thành một tệp khác để giữ tệp '/ test' của tôi nhỏ và dễ quản lý. Nó cũng cho phép bạn hợp lý các tuyến đường với nhau bằng đường dẫn URL có thể thực sự thuận tiện.

Nội dung của ./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);

Nội dung của ./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;

Nội dung của ./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
Đây là câu trả lời tốt nhất, nên đứng đầu danh sách! Cảm ơn bạn
Kostanos

Tôi có thể sử dụng cấu trúc này cho Node Js Rest API không?
MSM

@MSMurugan yep u có thể xây dựng một api còn lại với mẫu này.
ShortRound1911

@ ShortRound1911 Tôi đang xây dựng một api còn lại mẫu này và đặt vào máy chủ lưu trữ plesk, tôi đang gặp lỗi
MSM

96

Dựa trên ví dụ của @ShadowCloud, tôi có thể tự động bao gồm tất cả các tuyến đường trong một thư mục con.

tuyến đường / 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);
    });
}

Sau đó, đặt các tập tin tuyến đường trong thư mục tuyến đường như vậy:

tuyến / test1.js

module.exports = function(app){

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

    //other routes..
}

Lặp đi lặp lại điều đó nhiều lần tôi cần và cuối cùng là đặt app.js

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

1
Tôi thích cách tiếp cận này tốt hơn, cho phép thêm các tuyến mới mà không phải thêm bất cứ điều gì cụ thể vào tệp ứng dụng chính.
Jason Miesionczek

3
Thật tuyệt, tôi cũng sử dụng phương pháp này, với một kiểm tra bổ sung về phần mở rộng tệp vì tôi đã gặp phải vấn đề với các tệp swp.
Geekfish

Bạn cũng không phải sử dụng readdirSync w / this, readdir hoạt động tốt.
Paul

5
Có bất kỳ chi phí nào trong việc sử dụng phương pháp này để đọc các tệp trong thư mục so với chỉ yêu cầu các tuyến đường trong tệp app.js của bạn không?
Abadaba

Tôi cũng muốn biết giống như @Abadaba. Khi nào điều này được đánh giá, khi bạn khởi chạy máy chủ hoặc trên mọi yêu cầu?
bắt đầu

19

Và xây dựng thêm về câu trả lời trước, phiên bản tuyến / index.js này sẽ bỏ qua mọi tệp không kết thúc bằng .js (và chính nó)

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

Cảm ơn vì điều đó. Tôi đã có một người nào đó trên Mac thêm .DS_Storecác tập tin và nó đã làm mọi thứ rối tung lên.
JayQuerie.com

19

Định tuyến đệ quy đầy đủ của tất cả .jscác tệp trong /routesthư mục, đặt cái này vào 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

trong /routesbạn đặt whatevername.jsvà khởi tạo các tuyến đường của bạn như thế này:

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

Tôi đang cố gắng cập nhật câu trả lời này bằng "express": "^ 4.16.3". Câu trả lời này tương tự như 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;

Tôi hy vọng điều này có thể giúp đỡ một ai đó. Chúc mừng mã hóa!


8

Nếu bạn đang sử dụng nhanh-4.x với nguyên cảo và ES6, đây sẽ là mẫu tốt nhất để sử dụng:

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

Sạch hơn nhiều so với sử dụng varmodule.exports.


5

Một điều chỉnh cho tất cả các câu trả lời sau:

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

Chỉ cần sử dụng biểu thức chính quy để lọc qua kiểm tra từng tệp trong mảng. Nó không phải là đệ quy, nhưng nó sẽ lọc các thư mục không kết thúc bằng .js


5

Tôi biết đây là một câu hỏi cũ, nhưng tôi đã cố gắng tìm ra điều gì đó giống như bản thân mình và đây là nơi tôi đã kết thúc, vì vậy tôi muốn đưa giải pháp của mình cho một vấn đề tương tự trong trường hợp người khác gặp vấn đề tương tự tôi ' m có. Có một mô-đun nút đẹp ngoài kia gọi là uỷ thác mà hiện rất nhiều các công cụ hệ thống tập tin được nhìn thấy ở đây cho bạn (tức là - không có thứ readdirSync). Ví dụ:

Tôi có một ứng dụng API đầy đủ, tôi đang cố gắng xây dựng và tôi muốn đặt tất cả các yêu cầu đi đến '/ api / *' để được xác thực và tôi muốn lưu trữ tất cả các tuyến đường của mình trong api vào thư mục riêng của họ (hãy gọi nó là 'api'). Trong phần chính của ứng dụng:

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

Bên trong thư mục tuyến đường, tôi có một thư mục gọi là "api" và một tệp có tên api.js. Trong api.js, tôi chỉ cần có:

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;

Mọi thứ hoạt động như mong đợi. Hy vọng điều này sẽ giúp được ai đó.


5

Nếu bạn muốn một tệp .js riêng để tổ chức tốt hơn các tuyến đường của mình, chỉ cần tạo một biến trong app.jstệp trỏ đến vị trí của nó trong hệ thống tệp:

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

sau đó,

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

nơi .foolà một số chức năng khai báo trong của bạn wf.jstập tin. ví dụ

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

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

}

1
+1. Đây là cách tiếp cận được thể hiện trong ví dụ chính thức ở đây: github.com/strongloop/express/tree/master/examples/ chủ
Matt Browne

1
Điều này có hoạt động để chia sẻ các hàm và biến toàn cục trong app.js không? Hoặc bạn sẽ phải "chuyển" chúng vào wf.foo, v.v. vì chúng nằm ngoài phạm vi như với các giải pháp được trình bày khác? Tôi đang đề cập đến trường hợp thông thường bạn sẽ truy cập các biến / hàm được chia sẻ trong wf.foo nếu nó không được tách ra khỏi app.js.
David

đúng vậy, nếu bạn khai báo hàm 'foo' trong app.js thì app.get ('/ wf', foo); sẽ hoạt động
NiallJG


0

Đây có thể là câu hỏi / câu trả lời tràn ngăn xếp tuyệt vời nhất từng có. Tôi yêu các giải pháp của Sam / Brad ở trên. Tôi nghĩ rằng tôi sẽ hòa nhập với phiên bản async mà tôi đã triển khai:

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

Cấu trúc thư mục của tôi là một chút khác nhau. Tôi thường xác định các tuyến đường trong app.js (trong thư mục gốc của dự án) bằng cách require-ing './routes'. Do đó, tôi bỏ qua kiểm tra index.jsvì tôi cũng muốn bao gồm kiểm tra đó.

EDIT: Bạn cũng có thể đặt hàm này trong một hàm và gọi nó một cách đệ quy (tôi đã chỉnh sửa ví dụ để hiển thị điều này) nếu bạn muốn lồng các tuyến của mình vào các thư mục có độ sâu tùy ý.


2
Tại sao bạn muốn có một phiên bản aysnc? Có lẽ bạn muốn thiết lập tất cả các tuyến đường của mình trước khi bắt đầu phân phát lưu lượng truy cập nếu không bạn có thể sẽ gửi một số 404 'sai'.
Joe Abrams

6
Thật. Tôi đã viết nó trong khi vẫn học nút. Tôi đồng ý khi nhìn lại rằng nó không có ý nghĩa.
tandrewnichols

0

bạn có thể đặt tất cả các chức năng định tuyến trong các tệp (mô-đun) khác và liên kết nó với tệp máy chủ chính. trong tệp express chính, thêm một chức năng sẽ liên kết mô-đun với máy chủ:

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

và gọi chức năng đó cho từng mô hình tuyến đường:

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

trong các tệp mô-đun (ví dụ: tệp login.js), xác định các chức năng như bình thường:

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

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

và xuất nó với phương thức request là một khóa và giá trị là một mảng các đối tượng, mỗi đối tượng có các đường dẫn và các phím chức năng.

module.exports = {
   get: [{path:'/',func:login_screen}, {...} ],
   post: [{path:'/login:forgotPassword', func:forgot_password}]
};   
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.