Variável global em app.js acessível em rotas?

90

Como faço para definir uma variável app.jse tê-la disponível em todas as rotas, pelo menos no index.jsarquivo localizado nas rotas. usando a estrutura expressa enode.js

Technupe
fonte
1
O objeto app.locals possui propriedades que são variáveis ​​locais dentro do aplicativo. Em seu arquivo de rota, faça referência a ele com req.app.locals.
Ronnie Royston

Respostas:

63

Para fazer uma variável global, basta declará-la sem a varpalavra - chave. (De modo geral, essa não é a prática recomendada, mas em alguns casos pode ser útil - apenas tome cuidado, pois isso tornará a variável disponível em todos os lugares.)

Aqui está um exemplo de visionmedia / screenshot-app

arquivo app.js :

/**
 * Module dependencies.
 */

var express = require('express')
  , stylus = require('stylus')
  , redis = require('redis')
  , http = require('http');

app = express();

//... require() route files

arquivo rotas / main.js

//we can now access 'app' without redeclaring it or passing it in...

/*
 * GET home page.
 */

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

//...
Jesse Fulton
fonte
6
Como uma observação, geralmente é melhor ser explícito sobre passar variáveis ​​e instanciá-las, para que você não anule acidentalmente o ref em algum outro lugar do aplicativo, ou o que quer que seja.
Paul
3
Isso é realmente péssimo, como Paul observou. Eu sugeriria o padrão de injeção mencionado abaixo. Sim, mais código padrão para que não pareça "bonito", mas garante que seu código seja modular ... algo que você vai gostar se este não for seu último projeto;)
srquinn
Depende das circunstâncias IMHO. Sim, vars globais geralmente não são uma boa prática (como afirmei em minha resposta) e, ao começar do zero, diria que organize tudo em módulos separados. Mas se você estiver integrando com o código existente, muitas vezes há outras considerações - esta é uma solução (fácil, mas perigosa).
Jesse Fulton
2
Alguém poderia explicar por que isso funciona em referência à semântica do Javascript? A qual escopo é appassociado?
Ali
Não acho que essa resposta deva ser marcada como correctuma.
Code Cooker
91

Na verdade, é muito fácil fazer isso usando os métodos "set" e "get" disponíveis em um objeto expresso.

Exemplo a seguir, digamos que você tenha uma variável chamada config com as coisas relacionadas à configuração que deseja disponibilizar em outros lugares:

Em app.js:

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

app.configure(function() {
  ...
  app.set('config', config); 
  ...
}

Em routes / index.js

exports.index = function(req, res){
  var config = req.app.get('config');
  // config is now available
  ...
}
Mandy
fonte
Definir 'app' global? Sim. Mas este método é o melhor para nos salvar de problemas e caos.
diproart
52
para quem chega atrasado: app.configure é removido no expresso 4.x
zamil
Legal, req.app.get('name')funciona como um encanto. Esta propriedade contém uma referência à instância do aplicativo Express que está usando o middleware. expressjs.com/pt-br/api.html#req.app
Lazaro Fernandes Lima Suleiman
57

Uma maneira interessante de fazer isso é usar o app.localspróprio Express. Aqui está a documentação.

// In app.js:
app.locals.variable_you_need = 42;

// In index.js
exports.route = function(req, res){
    var variable_i_needed = req.app.locals.variable_you_need;
}
Todos
fonte
1
Usei esse método para localizar serviços http e substituí-los facilmente em testes de unidade.
Alex
28

Para declarar uma variável global, você precisa usar objeto global . Como global.yourVariableName. Mas não é um caminho verdadeiro. Para compartilhar variáveis ​​entre módulos, tente usar o estilo de injeção como

someModule.js:

module.exports = function(injectedVariable) {
    return {
        somePublicMethod: function() {
        },
        anotherPublicMethod: function() {
        },
    };
};

app.js

var someModule = require('./someModule')(someSharedVariable);

Ou você pode usar um objeto substituto para fazer isso. Como hub .

someModule.js:

var hub = require('hub');

module.somePublicMethod = function() {
    // We can use hub.db here
};

module.anotherPublicMethod = function() {
};

app.js

var hub = require('hub');
hub.db = dbConnection;
var someModule = require('./someModule');
Vadim Baryshev
fonte
7

Aqui estão uma explicação bem, em suma:

http://www.hacksparrow.com/global-variables-in-node-js.html

Então, você está trabalhando com um conjunto de módulos Node, talvez uma estrutura como Express.js, e de repente sente a necessidade de tornar algumas variáveis ​​globais. Como você torna as variáveis ​​globais no Node.js?

O conselho mais comum para este é "declarar a variável sem a palavra-chave var" ou "adicionar a variável ao objeto global" ou "adicionar a variável ao objeto GLOBAL". Qual destes você usa?

Primeiro, vamos analisar o objeto global. Abra um terminal, inicie um Node REPL (prompt).

> global.name
undefined
> global.name = 'El Capitan'
> global.name
'El Capitan'
> GLOBAL.name
'El Capitan'
> delete global.name
true
> GLOBAL.name
undefined
> name = 'El Capitan'
'El Capitan'
> global.name
'El Capitan'
> GLOBAL.name
'El Capitan'
> var name = 'Sparrow'
undefined
> global.name
'Sparrow'
Victor Cruz
fonte
No Express - ao usar jshint ou linting, em geral - isso se torna um problema.
Steven Ventimiglia
6

a maneira mais fácil é declarar uma variável global em seu app.js, desde o início:

global.mySpecialVariable = "something"

então, em qualquer rota, você pode obtê-lo:

console.log(mySpecialVariable)
Xamã
fonte
1
No Express - ao usar jshint ou linting, em geral - isso se torna um problema.
Steven Ventimiglia
5

Esta foi uma pergunta útil, mas poderia ser ainda mais fornecendo exemplos de código reais. Mesmo o artigo vinculado não mostra realmente uma implementação. Eu, portanto, humildemente submeto:

No seu app.jsarquivo, a parte superior do arquivo:

var express = require('express')
, http = require('http')
, path = require('path');

app = express(); //IMPORTANT!  define the global app variable prior to requiring routes!

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

app.js não terá nenhuma referência ao app.get()método. Deixe-os para serem definidos nos arquivos de rotas individuais.

routes/index.js:

require('./main');
require('./users');

e, finalmente, um arquivo de rotas real routes/main.js:

function index (request, response) {
    response.render('index', { title: 'Express' });
}

app.get('/',index); // <-- define the routes here now, thanks to the global app variable
John Gordon
fonte
4

Minha maneira preferida é usar dependências circulares *, cujo nó suporta

  • em app.js define var app = module.exports = express();como sua primeira ordem de negócios
  • Agora, qualquer módulo necessário após o fato pode var app = require('./app')acessá-lo


app.js

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

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

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


rotas / 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');
Will Stern
fonte
Ótima dica. Acabei de mudar do método require ('./ myroutes') (app) para fazer isso e bati minha cabeça contra a parede por 10 minutos tentando descobrir por que nenhuma de minhas rotas funcionou. Não se esqueça de retirar especificações de rota em myroutes.js de um bloco de funções. Doh!
Greg
2

Como outros já compartilharam, app.set('config', config)é ótimo para isso. Eu só queria acrescentar algo que não vi nas respostas existentes que é muito importante. Uma instância do Node.js é compartilhada entre todas as solicitações, portanto, embora possa ser muito prático compartilhar alguns configou routerobjetos globalmente, o armazenamento de dados de tempo de execução globalmente estará disponível nas solicitações e usuários . Considere este exemplo muito simples:

var express = require('express');
var app = express();

app.get('/foo', function(req, res) {
    app.set('message', "Welcome to foo!");
    res.send(app.get('message'));
});

app.get('/bar', function(req, res) {
    app.set('message', "Welcome to bar!");

    // some long running async function
    var foo = function() {
        res.send(app.get('message'));
    };
    setTimeout(foo, 1000);
});

app.listen(3000);

Se você visitar /bare outro pedido /fooaparecer, sua mensagem será "Bem-vindo ao foo!". Este é um exemplo bobo, mas mostra o que quero dizer.

Existem alguns pontos interessantes sobre isso em Por que diferentes sessões de node.js compartilham variáveis? .

Charlie Schliesser
fonte
1

Resolvi o mesmo problema, mas tive que escrever mais código. Criei um server.jsarquivo, que usa expresso para cadastrar rotas. Ele expõe uma função,, registerque pode ser usada por outros módulos para registrar suas próprias rotas. Ele também expõe uma função startServer, para começar a escutar uma porta

server.js

const express = require('express');
const app = express();

const register = (path,method,callback) => methodCalled(path, method, callback)

const methodCalled = (path, method, cb) => {
  switch (method) {
    case 'get':
      app.get(path, (req, res) => cb(req, res))
      break;
    ...
    ...  
    default:
      console.log("there has been an error");
  }
}

const startServer = (port) => app.listen(port, () => {console.log(`successfully started at ${port}`)})

module.exports = {
  register,
  startServer
}

Em outro módulo, use este arquivo para criar uma rota.

help.js

const app = require('../server');

const registerHelp = () => {
  app.register('/help','get',(req, res) => {
    res.send("This is the help section")
  }),
  app.register('/help','post',(req, res) => {
    res.send("This is the help section")
  })}

module.exports = {
  registerHelp
}

No arquivo principal, inicialize ambos.

app.js

require('./server').startServer(7000)
require('./web/help').registerHelp()
Amar Dev
fonte
0

A resposta de John Gordon foi a primeira de dezenas de respostas meio explicadas / documentadas que tentei, em muitos, muitos sites, que realmente funcionaram. Obrigado, Sr. Gordon. Desculpe, não tenho pontos para aumentar sua resposta.

Eu gostaria de adicionar, para outros novatos em node-route-file-splitting, que o uso da função anônima para 'índice' é o que se verá com mais frequência, portanto, usando o exemplo de John para main.js, o funcionalmente código equivalente que normalmente encontraria é:

app.get('/',(req, res) {
    res.render('index', { title: 'Express' });
});
JosephK
fonte
0

Eu usei app.all

O método app.all () é útil para mapear a lógica "global" para prefixos de caminho específicos ou correspondências arbitrárias.

No meu caso, estou usando confit para gerenciamento de configuração,

app.all('*', function (req, res, next) {
    confit(basedir).create(function (err, config) {
        if (err) {
            throw new Error('Failed to load configuration ', err);
        }
        app.set('config', config);
        next();
    });
});

Nas rotas, você simplesmente faz req.app.get('config').get('cookie');

nilesh
fonte
-1

isso é muito fácil, mas as respostas das pessoas são confusas e complexas ao mesmo tempo.

deixe-me mostrar como você pode definir uma variável global em seu expressaplicativo. Assim, você pode acessá-lo de qualquer rota, conforme necessário.

Digamos que você queira definir uma variável global de sua /rota principal

router.get('/', (req, res, next) => {

  req.app.locals.somethingNew = "Hi setting new global var";
});

Portanto, você obterá req.app de todas as rotas. e então você terá que usar o localspara definir os dados globais em. como mostrado acima, você está pronto. agora vou mostrar como usar esses dados

router.get('/register', (req, res, next) => {

  console.log(req.app.locals.somethingNew);
});

Como acima, da registerrota que você está acessando, os dados foram configurados anteriormente.

É assim que você pode fazer isso funcionar!

Code Cooker
fonte