Express : 앱 인스턴스를 다른 파일의 경로로 전달하는 방법은 무엇입니까?


103

내 경로를 다른 파일로 나누고 싶습니다. 한 파일에는 모든 경로가 포함되고 다른 파일에는 해당 작업이 포함됩니다. 현재이를 달성 할 수있는 솔루션이 있지만 작업에서 액세스 할 수 있도록 앱 인스턴스를 전역으로 만들어야합니다. 내 현재 설정은 다음과 같습니다.

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.

};

controllers / index.js :

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

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

controllers / posts.js :

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

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

그러나이 설정에는 큰 문제가 있습니다. 작업 (controllers / *. js)에 전달해야하는 데이터베이스 및 앱 인스턴스가 있습니다. 내가 생각할 수있는 유일한 옵션은 두 변수를 모두 전역으로 만드는 것인데, 이는 실제로 해결책이 아닙니다. 경로가 많고 중앙에 위치하기를 원하기 때문에 작업에서 경로를 분리하고 싶습니다.

작업에 변수를 전달하고 경로에서 작업을 분리하는 가장 좋은 방법은 무엇입니까?


controllers.js는 어떻게 생겼습니까? 매개 변수를받을 수있는 함수 (객체 대신)로 만들 수 있습니다.
mihai

require ( 'controllers')에는 controllers / index.js가 필요합니다. 그러나 라우트 (route.js 참조)에서 객체를 사용하기 때문에 함수가 작동하지 않으므로 함수 인 경우에도 인수를 전달할 수 없습니다.
Claudio Albertin 2012

답변:


165

사용 req.app,req.app.get('somekey')

호출 express()에 의해 생성 된 애플리케이션 변수 는 요청 및 응답 객체에 설정됩니다.

참조 : https://github.com/visionmedia/express/blob/76147c78a15904d4e4e469095a29d1bec9775ab6/lib/express.js#L34-L35


감사. 이것이 app.set ( 'name', val);로 설정된 변수에 액세스하는 가장 좋은 방법이라고 생각합니다.
Pavel Kostenko 2013

4
전화하는 것을 잊지 마세요 app.set('somekey', {})app.js에
ankitjaininfo

3
이 방법에 대한 유일한 불만은 app.locals.authorized (main.js app.route('/something').get(app.locals.authorized,function(req,res,next){});가 아님 )를 실행하려고 할 때 req 범위 밖에 있기 때문에 불가능하다는 것입니다.
gabeio

다른 쿼리 매개 변수에 대해 다른 여권 전략을 사용하고 있습니다. 그래서 미들웨어에 passport.use ( "strategy-name")를 설정하려고합니다. let passport = req.app, get ( 'passport')로만 해당 미들웨어에 여권을 저장하더라도. 다른 요청 세트에 대해 수정 중입니다. 왜 그래야만하지 ?
Kartikeya Mishra

이렇게하면 req 객체에 redis 및 db와 같은 추가 Object 인스턴스가 있습니다. 애플리케이션 성능에 영향을주지 않습니까? 예 : index.js에서 app.set ( 'redis', redis_client); 경로 /example.js 라우터 = require ( 'express'). Router (); route.get ( '/ test', (req, res, next) => {conosle.log (req.app.get ( 'redis')); return res.send ( "// done");})
Suz Aann shrestha

101

Node.js는 순환 종속성을 지원합니다.
require ( './ routes') (app) 대신 순환 종속성을 사용하면 많은 코드가 정리되고 각 모듈이로드 파일에 덜 상호 의존하게됩니다.


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


----- 2014 년 4 월 업데이트 -----
Express 4.0은 express.router () 메서드를 추가하여 경로를 정의하는 사용 사례를 수정했습니다!
문서 -http : //expressjs.com/4x/api.html#router

새 생성기의 예 :
경로 작성 :
https://github.com/expressjs/generator/blob/master/templates/js/routes/index.js
앱에 추가 / 이름 간격 지정 : https://github.com /expressjs/generator/blob/master/templates/js/app.js#L24

여전히 다른 리소스에서 앱에 액세스하는 사용 사례가 있으므로 순환 종속성은 여전히 ​​유효한 솔루션입니다.


1
"로드하는 파일에 덜 상호 의존적"-로드하는 파일의 특정 파일 경로 에 따라 다릅니다 . 그것은 매우 긴밀한 결합이므로 그렇지 않은 척하지 마십시오.
Camilo Martin

2
앱을 내 보낸 app.js 라우팅 파일이 필요 하므로 매우주의하십시오 (읽기 : 지난 한 시간 동안 어려움을 겪은 일을하지 마십시오 +) . 순환 호출은 정말 엉망이 될 수 있으므로 작동 방식 을 알고 있어야 합니다 ! require()
Nateowami

솔직히 req.app.get ( 'somekey') 사용에 대한 @Feng의 대답이 실제로 서큘러 종속성을 사용하는 것보다 더 좋고 깨끗한 솔루션이라고 생각합니다.
Claudio Mezzasalma

@Green 앱이 비어 있으면 앱이 정의 되기 app전에 필요한 파일이 필요합니다 module.exports. 인스턴스화 app하고 설정 module.exports한 다음 필요한 파일을 요구해야합니다. app 그러나 어느 쪽이든 순환 종속성을 수행하는 것은 표현이 해결 한 안티 패턴입니다. 더 이상 그렇게 할 필요가 없습니다.
Will Stern

26

주석에서 말했듯이 함수를 module.exports로 사용할 수 있습니다. 함수도 객체이므로 구문을 변경할 필요가 없습니다.

app.js

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

controllers.js

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

controllers / index.js

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

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

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

module.exports = controllers;

함수 내에서 객체를 반환해도됩니까? 아니면 예제에서와 같이 메서드를 설정하는 것이 더 낫습니까?
Claudio Albertin 2012

어느 쪽이든 괜찮다고 생각합니다.
mihai

메서드가 많기 때문에 각각 수동으로 설정하는 대신 개체로 설정하는 것을 선호합니다. 이것은 내가 객체를 반환하면 작동하지만 조금 더 평평한 해결책이 없습니까? 내 실제 방법은 ... 두 번 들여 쓰기 될 것이다
클라우디오 Albertin에게

나는 당신을 이해하지만 추측 확실하지 경우는 구현 외부 이동할 수있는 controllers기능과 같은 : jsfiddle.net/mihaifm/yV79K
미하이

controllers / index.js는 컨트롤러 var를 반환 할 필요가 없습니까?
Yalamber

5

아니면 그냥하세요 :

var app = req.app

이러한 경로에 사용중인 미들웨어 내부. 그렇게 :

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

누군가 왜 이것이 허용되지 않는 대답인지 말해줍니다. @Fengapp.use('my-service', serviceInstance)req.app.get('my-service')
Felipe가

0

"contollers"라는 폴더가 있다고 가정 해 보겠습니다.

app.js에 다음 코드를 넣을 수 있습니다.

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

... 그리고 ...

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

컨트롤러 이전 버전에는 다음 코드와 함께 "ping.js"파일이 있습니다.

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

그리고이게 ....


0
  1. 모든 컨트롤러에 db 객체를 전달하지 않고 모든 컨트롤러에 액세스 할 수 있도록하려면 db 객체를 모든 req 객체에 연결하는 애플리케이션 수준 미들웨어를 만든 다음 모든 컨트롤러에서 액세스 할 수 있습니다.
// app.js
let db = ...;  // your db object initialized
const contextMiddleware = (req, res, next) => {
  req.db=db;
  next();
};
app.use(contextMiddleware);
  1. 모든 곳에 앱 인스턴스를 전달하지 않도록 대신 앱이있는 위치로 경로를 전달합니다.
// 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

최종 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');
});

다른 버전 : 게시 요청 추가와 같이 필요에 따라 맞춤 설정할 수 있습니다.

// 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

데이터베이스의 경우 모든 DB 작업을 간단한 API로 수행하고 공유 상태를 피하는 데이터 액세스 서비스를 분리합니다.

route.setup을 분리하는 것은 오버 헤드처럼 보입니다. 대신 구성 기반 라우팅을 배치하고 싶습니다. .json 또는 주석으로 경로를 구성합니다.


데이터 액세스 서비스 란 무엇을 의미합니까? 어떻게 생겼을까 요?
Claudio Albertin 2012

내 실제 route.js 파일은 훨씬 더 크고 express-namespaces 모듈을 사용합니다. 작업에서 경로를 어떻게 분리 하시겠습니까?
Claudio Albertin 2012
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.