Ekspres: Uygulama örneğini farklı bir dosyadan rotalara nasıl geçirebilirim?


104

Rotalarımı farklı dosyalara bölmek istiyorum, burada bir dosya tüm rotaları içerir ve diğeri ilgili eylemleri içerir. Şu anda bunu başarmak için bir çözümüm var, ancak eylemlerde ona erişebilmek için uygulama örneğini global yapmam gerekiyor. Mevcut kurulumum şöyle görünüyor:

app.js:

var express   = require('express');
var app       = express.createServer();
var routes    = require('./routes');

var controllers = require('./controllers');
routes.setup(app, controllers);

app.listen(3000, function() {
  console.log('Application is listening on port 3000');
});

route.js:

exports.setup = function(app, controllers) {

  app.get('/', controllers.index);
  app.get('/posts', controllers.posts.index);
  app.get('/posts/:post', controllers.posts.show);
  // etc.

};

denetleyiciler / index.js:

exports.posts = require('./posts');

exports.index = function(req, res) {
  // code
};

denetleyiciler / posts.js:

exports.index = function(req, res) {
  // code
};

exports.show = function(req, res) {
  // code
};

Ancak, bu kurulumun büyük bir sorunu var: Eylemlere (denetleyiciler / *. Js) aktarmam gereken bir veritabanı ve uygulama örneğim var. Aklıma gelen tek seçenek, her iki değişkeni de küresel yapmaktır ki bu gerçekten bir çözüm değildir. Rotaları eylemlerden ayırmak istiyorum çünkü çok fazla rotam var ve onları merkezi bir yerde istiyorum.

Değişkenleri eylemlere aktarmanın ancak eylemleri rotalardan ayırmanın en iyi yolu nedir?


Controllers.js nasıl görünüyor? Belki bunu parametreleri alabilen bir işlev (bir nesne yerine) yapabilirsiniz.
mihai

require ('denetleyiciler'), denetleyiciler / index.js gerektirir. Ancak, nesneyi rotalarda kullandığım için (route.js'ye bakın) bir işlev çalışmaz ve bu nedenle bir işlev olsa bile ona argümanlar iletemiyorum.
Claudio Albertin

Yanıtlar:


166

Kullanım req.app,req.app.get('somekey')

Çağırarak oluşturulan uygulama değişkeni express(), istek ve yanıt nesnelerinde ayarlanır.

Bakınız: https://github.com/visionmedia/express/blob/76147c78a15904d4e4e469095a29d1bec9775ab6/lib/express.js#L34-L35


Teşekkürler. Bunun app.set ('name', val) ile ayarlanan değişkenlere erişmenin en iyi yolu olduğunu düşünüyorum;
Pavel Kostenko

4
app.set('somekey', {})App.js'de aramayı unutmayın
ankitjaininfo

3
Bu yolla ilgili tek yakınmam, bunu sevmeme rağmen, bir app.locals.authorized gibi yetkilendirilmiş bir uygulamayı çalıştırmaya çalıştığınızda (main.js'de değil): bu app.route('/something').get(app.locals.authorized,function(req,res,next){});, gerekli kapsamın dışında olduğu için mümkün değildir.
gabeio

Farklı sorgu parametreleri için farklı pasaport stratejisi kullanıyorum. Bu yüzden bir ara yazılımda passport.use ("strateji adı") ayarlamaya çalışıyorum. Bu ara yazılımda pasaportu yalnızca let passport = req.app ile saklasam bile, get ('passport'). Başka bir istek grubu için değiştiriliyor. Neden böyle?
Kartikeya Mishra

Bunu yaparsam, benim durumumda req nesnesinin redis ve db gibi ek Object örnekleri olacaktır. Uygulama performansını etkilemeyecek mi? örneğin: index.js app.set ('redis', redis_client) içinde; yollarda / example.js yönlendirici = gerektirir ('ekspres'). Yönlendirici (); route.get ('/ test', (req, res, next) => {conosle.log (req.app.get ('redis')); dönüş res.send ("// bitti");})
Suz Aann shrestha

101

Node.js döngüsel bağımlılıkları destekler.
Require ('./ route') (app) yerine döngüsel bağımlılıkları kullanmak, çok sayıda kodu temizler ve her modülü yükleme dosyasına daha az bağımlı hale getirir:


app.js

var app = module.exports = express(); //now app.js can be required to bring app into any file

//some app/middleware setup, etc, including 
app.use(app.router);

require('./routes'); //module.exports must be defined before this line


route / index.js

var app = require('../app');

app.get('/', function(req, res, next) {
  res.render('index');
});

//require in some other route files...each of which requires app independently
require('./user');
require('./blog');


----- 04/2014 güncellemesi -----
Express 4.0, bir express.router () yöntemi ekleyerek rotaları tanımlamak için kullanım durumunu düzeltti!
belgeler - http://expressjs.com/4x/api.html#router

Yeni oluşturucularından örnek:
Rotayı yazma:
https://github.com/expressjs/generator/blob/master/templates/js/routes/index.js Uygulamaya
ekleme / ad alanı ekleme: https://github.com /expressjs/generator/blob/master/templates/js/app.js#L24

Uygulamaya diğer kaynaklardan erişmek için hala kullanım alanları vardır, bu nedenle döngüsel bağımlılıklar hala geçerli bir çözümdür.


1
"'s yükleme dosyasına daha az bağımlı" - bu belirli bağımlı olduğunu filepath onun yükleme dosyasının. Bu çok sıkı bir bağlantı, o yüzden öyle değilmiş gibi davranmayalım.
Camilo Martin

2
Uygulamayı dışa app.jsaktardıktan sonra yönlendirme dosyasına ihtiyacınız olduğuna çok dikkat edin (okuyun: son bir saattir uğraştığım şeyi yapma +) . Dairesel require()aramalar gerçek bir karmaşa yaratabilir, bu yüzden nasıl çalıştıklarını bildiğinizden emin olun !
Nateowami

Dürüst olmak gerekirse, @Feng'in req.app.get ('somekey') kullanımıyla ilgili cevabının circulr bağımlılıklarını kullanmaktan daha iyi ve daha temiz bir çözüm olduğunu düşünüyorum.
Claudio Mezzasalma

@ Yeşil uygulama boşsa, appuygulama module.exportstanımlanmadan ÖNCE gereken bir dosya gerekiyordu . Gerekli olabilecek dosyaları başlatmalı app, ayarlamalı module.exportsve talep etmelisiniz. app Ancak her iki durumda da, döngüsel bağımlılıkları yapmak, çözülmüş bir anti-modeldir - artık bunu yapmanıza gerek yok.
Will Stern

26

Yorumlarda söylediğim gibi, module.exports olarak bir işlev kullanabilirsiniz. Bir işlev aynı zamanda bir nesnedir, bu nedenle sözdiziminizi değiştirmeniz gerekmez.

app.js

var controllers = require('./controllers')({app: app});

controllers.js

module.exports = function(params)
{
    return require('controllers/index')(params);
}

denetleyiciler / index.js

function controllers(params)
{
  var app = params.app;

  controllers.posts = require('./posts');

  controllers.index = function(req, res) {
    // code
  };
}

module.exports = controllers;

İşlevin içindeki bir nesneyi döndürmek doğru mu yoksa daha iyi mi, bu yüzden yöntemleri örneğinizde yaptığınız gibi ayarlayın?
Claudio Albertin

bence her iki yaklaşım da tamam.
mihai

Çok fazla yöntemim olduğu için, bunları manuel olarak yerine bir nesne olarak ayarlamayı tercih ederim. Bu, sadece nesneyi iade ettiğimde işe yarar, ancak biraz daha düz olan bir çözüm yok mu? Benim gerçek yöntemler ... İki kez girintili olacağını
Claudio Albertin

Sizi anladığımdan emin değilim, ancak uygulamayı bu controllersişlevin dışına taşıyabilirsiniz, şuna
mihai

denetleyiciler / index.js'nin denetleyicileri var döndürmesi gerekmez mi?
Yalamber

5

Ya da sadece şunu yapın:

var app = req.app

Middleware içinde bu rotalar için kullandığınız. Bunun gibi:

router.use( (req,res,next) => {
    app = req.app;
    next();
});

Biri bana bunun neden kabul edilen cevap olmadığını söyledi mi? @Fengapp.use('my-service', serviceInstance)req.app.get('my-service')
Felipe

0

"Contollers" adlı bir klasörünüz olduğunu varsayalım.

App.js dosyanıza şu kodu koyabilirsiniz:

console.log("Loading controllers....");
var controllers = {};

var controllers_path = process.cwd() + '/controllers'

fs.readdirSync(controllers_path).forEach(function (file) {
    if (file.indexOf('.js') != -1) {
        controllers[file.split('.')[0]] = require(controllers_path + '/' + file)
    }
});

console.log("Controllers loaded..............[ok]");

... ve ...

router.get('/ping', controllers.ping.pinging);

Daha önce denetleyicilerinizde şu kodla "ping.js" dosyasına sahip olacaksınız:

exports.pinging = function(req, res, next){
    console.log("ping ...");
}

Ve işte bu....


0
  1. Db nesnenizi her yere iletmeden tüm denetleyiciler için erişilebilir kılmak için: db nesnesini her gerekli nesneye ekleyen uygulama düzeyinde bir ara yazılım oluşturun, ardından ona her denetleyiciden erişebilirsiniz.
// app.js
let db = ...;  // your db object initialized
const contextMiddleware = (req, res, next) => {
  req.db=db;
  next();
};
app.use(contextMiddleware);
  1. uygulama örneğini her yere iletmekten kaçınmak yerine, rotaları uygulamanın bulunduğu yere
// routes.js  It's just a mapping.
exports.routes = [
  ['/', controllers.index],
  ['/posts', controllers.posts.index],
  ['/posts/:post', controllers.posts.show]
];

// app.js
var { routes }    = require('./routes');
routes.forEach(route => app.get(...route));
// You can customize this according to your own needs, like adding post request

Son app.js:

// app.js
var express   = require('express');
var app       = express.createServer();

let db = ...;  // your db object initialized
const contextMiddleware = (req, res, next) => {
  req.db=db;
  next();
};
app.use(contextMiddleware);

var { routes }    = require('./routes');
routes.forEach(route => app.get(...route));

app.listen(3000, function() {
  console.log('Application is listening on port 3000');
});

Başka bir sürüm: bunu gönderi isteği eklemek gibi kendi ihtiyaçlarınıza göre özelleştirebilirsiniz

// routes.js  It's just a mapping.
let get = ({path, callback}) => ({app})=>{
  app.get(path, callback);
}
let post = ({path, callback}) => ({app})=>{
  app.post(path, callback);
}
let someFn = ({path, callback}) => ({app})=>{
  // ...custom logic
  app.get(path, callback);
}
exports.routes = [
  get({path: '/', callback: controllers.index}),
  post({path: '/posts', callback: controllers.posts.index}),
  someFn({path: '/posts/:post', callback: controllers.posts.show}),
];

// app.js
var { routes }    = require('./routes');
routes.forEach(route => route({app}));

-1

Veritabanı için, tüm DB işini basit API ile yapacak ve paylaşılan durumdan kaçınacak olan Veri Erişim Hizmetini ayırın.

Rota ayırma. Kurulum ek yük gibi görünüyor. Bunun yerine konfigürasyona dayalı bir yönlendirme yerleştirmeyi tercih ederim. Ve rotaları .json biçiminde veya ek açıklamalarla yapılandırın.


Bir Veri Erişim Hizmeti ile ne demek istiyorsunuz? Nasıl görünürdü?
Claudio Albertin

Benim gerçek route.js dosyam çok daha büyük ve ekspres ad alanları modülünü kullanıyor. Rotaları eylemlerden nasıl ayırırsınız?
Claudio Albertin
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.