Глобальная переменная в app.js доступна в маршрутах?

91

Как мне установить переменную app.jsи сделать так, чтобы она была доступна во всех маршрутах, по крайней мере в index.jsфайле, расположенном в routes. используя экспресс-фреймворк иnode.js

Technupe
источник
1
Объект app.locals имеет свойства, которые являются локальными переменными в приложении. В файле маршрута укажите на него ссылку req.app.locals.
Ронни Ройстон

Ответы:

65

Чтобы создать глобальную переменную, просто объявите ее без varключевого слова. (Вообще говоря, это не лучшая практика, но в некоторых случаях она может быть полезна - просто будьте осторожны, так как это сделает переменную доступной везде.)

Вот пример из Visionmedia / screenshot-app

файл app.js :

/**
 * Module dependencies.
 */

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

app = express();

//... require() route files

файл routes / 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');
});

//...
Джесси Фултон
источник
6
В качестве примечания, как правило, лучше явно указывать на передачу переменных и их создание, чтобы случайно не обнулить ссылку где-нибудь еще в приложении или что-то еще.
Пол
3
Как заметил Пол, это действительно дурной тон. Я бы предложил схему инъекции, упомянутую ниже. Да, больше кода шаблона, чтобы он не выглядел «красиво», но он гарантирует, что ваш код является модульным ... что-то вам понравится, если это не ваш последний проект;)
srquinn
ИМХО, это зависит от обстоятельств. Да, глобальные вары, как правило, не являются хорошей практикой (как я сказал в своем ответе), и, начиная с нуля, я бы сказал, что организовывать все в отдельные модули. Но если вы интегрируетесь с существующим кодом, часто возникают другие соображения - это просто одно (простое, но опасное) решение.
Джесси Фултон,
2
Может ли кто-нибудь объяснить, почему это работает со ссылкой на семантику Javascript? С какой областью appсвязана?
Али
Я не думаю, что этот ответ следует отметить как correctтаковой.
Code Cooker,
93

На самом деле это очень легко сделать, используя методы «set» и «get», доступные для экспресс-объекта.

Пример, приведенный ниже, скажем, у вас есть переменная с именем config с вашими настройками, которые вы хотите сделать доступными в других местах:

В app.js:

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

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

В routes / index.js

exports.index = function(req, res){
  var config = req.app.get('config');
  // config is now available
  ...
}
Мэнди
источник
Установить глобальное приложение? Да. Но этот метод лучше всего избавит нас от проблем и хаоса.
diproart
53
для опоздавших: app.configure удален в экспресс 4.x
zamil
Красиво, req.app.get('name')работает как шарм. Это свойство содержит ссылку на экземпляр приложения Express, использующего промежуточное ПО. expressjs.com/pt-br/api.html#req.app
Ласаро Фернандес Лима Сулейман
58

Удобный способ сделать это - использовать app.localsсам Express. Вот документация.

// 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;
}
Али
источник
1
Я использовал этот метод, чтобы найти службы http и легко переопределить их в модульных тестах.
Alex
28

Чтобы объявить глобальную переменную, вам нужно использовать глобальный объект. Как global.yourVariableName. Но это неверный путь. Чтобы разделить переменные между модулями, попробуйте использовать стиль инъекции, например

someModule.js:

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

app.js

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

Или вы можете использовать для этого суррогатный объект. Нравится хаб .

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');
Вадим Барышев
источник
7

Вот краткое объяснение:

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

Итак, вы работаете с набором модулей Node, возможно, с фреймворком вроде Express.js, и внезапно чувствуете необходимость сделать некоторые переменные глобальными. Как сделать переменные глобальными в Node.js?

Самый распространенный совет - либо «объявить переменную без ключевого слова var», либо «добавить переменную к глобальному объекту», либо «добавить переменную к глобальному объекту». Какой ты используешь?

Прежде всего, давайте проанализируем глобальный объект. Откройте терминал, запустите Node REPL (приглашение).

> 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'
Виктор Круз
источник
В Express - при использовании jshint или линтинга вообще - это становится проблемой.
Стивен Вентимилья
6

Самый простой способ - заранее объявить глобальную переменную в app.js:

global.mySpecialVariable = "something"

то по любым маршрутам его можно получить:

console.log(mySpecialVariable)
Шаман
источник
1
В Express - при использовании jshint или линтинга вообще - это становится проблемой.
Стивен Вентимилья
5

Это был полезный вопрос, но его можно было бы улучшить, если бы приводились реальные примеры кода. Даже в связанной статье фактически не показана реализация. Поэтому я смиренно утверждаю:

В вашем app.jsфайле верхняя часть файла:

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 не будет иметь каких - либо ссылок на app.get()метод. Оставьте их определять в отдельных файлах маршрутов.

routes/index.js:

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

и, наконец, фактический файл маршрутов 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
Джон Гордон
источник
4

Я предпочитаю использовать круговые зависимости *, которые узел поддерживает

  • в app.js определите var app = module.exports = express();как ваше первое дело
  • Теперь любой модуль, необходимый постфактум, может var app = require('./app')получить к нему доступ


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


маршруты / 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');
Уилл Стерн
источник
Отличный совет. Я просто перешел от метода require ('./ myroutes') (app) к этому и в течение 10 минут бился головой о стену, пытаясь понять, почему ни один из моих маршрутов не сработал. Не забудьте взять спецификации маршрута в myroutes.js из функционального блока. Дох!
greg
2

Как уже поделились другие, app.set('config', config)отлично подходит для этого. Я просто хотел добавить кое-что, чего я не видел в существующих ответах, что очень важно. Экземпляр Node.js используется для всех запросов, поэтому, хотя может быть очень практичным делиться некоторыми configили routerобъектами глобально, глобальное хранение данных времени выполнения будет доступно для запросов и пользователей . Рассмотрим этот очень простой пример:

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

Если вы зайдете /barи получите другой запрос /foo, ваше сообщение будет «Добро пожаловать в foo!». Это глупый пример, но он передает суть.

Есть несколько интересных моментов по этому поводу в Почему разные сеансы node.js используют общие переменные? .

Чарли Шлиссер
источник
1

Я решил ту же проблему, но мне пришлось написать больше кода. Я создал server.jsфайл, в котором для регистрации маршрутов используется экспресс. Он предоставляет функцию, registerкоторая может использоваться другими модулями для регистрации своих собственных маршрутов. Он также предоставляет функцию startServer, чтобы начать прослушивание порта

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
}

В другом модуле используйте этот файл для создания маршрута.

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
}

В основном файле загрузите оба файла.

app.js

require('./server').startServer(7000)
require('./web/help').registerHelp()
Амар Дев
источник
0

Ответ Джона Гордона был первым из десятков полуобъясненных / задокументированных ответов, которые я попробовал на многих, многих сайтах, которые действительно сработали. Спасибо, мистер Гордон. Извините, у меня нет очков, чтобы отметить ваш ответ.

Я хотел бы добавить, для других новичков в разделении файла-маршрута-узла, что использование анонимной функции для 'индекса' - это то, что можно будет увидеть чаще, поэтому, используя пример Джона для main.js, функционально - эквивалентный код, который обычно можно найти:

app.get('/',(req, res) {
    res.render('index', { title: 'Express' });
});
JosephK
источник
0

Я использовал app.all

Метод app.all () полезен для отображения «глобальной» логики для определенных префиксов пути или произвольных совпадений.

В моем случае я использую confit для управления конфигурацией,

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

В маршрутах вы просто делаете req.app.get('config').get('cookie');

нилеш
источник
0

это довольно простая вещь, но ответы людей сбивают с толку и в то же время сложны.

позвольте мне показать вам, как вы можете установить глобальную переменную в вашем express приложении. Таким образом, вы можете получить к нему доступ с любого маршрута по мере необходимости.

Допустим, вы хотите установить глобальную переменную из своего основного /маршрута.

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

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

Таким образом, вы получите req.app со всех маршрутов. а затем вам нужно будет использовать localsдля установки глобальных данных. как показано выше, вы все настроены. сейчас я покажу вам, как использовать эти данные

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

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

Как указано выше из register маршрута, к которому вы обращаетесь, данные были установлены ранее.

Вот как можно заставить эту штуку работать!

Код Cooker
источник