Global Variable w app.js dostępne na trasach?

91

Jak ustawić zmienną w programie app.jsi mieć ją dostępną we wszystkich trasach, przynajmniej w index.jspliku znajdującym się w trasach. przy użyciu ekspresowych ram inode.js

Technupe
źródło
1
Obiekt app.locals ma właściwości, które są zmiennymi lokalnymi w aplikacji. W pliku trasy odwołaj się do niego z req.app.locals.
Ronnie Royston

Odpowiedzi:

65

Aby utworzyć zmienną globalną, po prostu zadeklaruj ją bez varsłowa kluczowego. (Ogólnie rzecz biorąc, nie jest to najlepsza praktyka, ale w niektórych przypadkach może być przydatna - po prostu bądź ostrożny, ponieważ spowoduje to, że zmienna będzie dostępna wszędzie.)

Oto przykład z aplikacji visionmedia / screenshot

plik app.js :

/**
 * Module dependencies.
 */

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

app = express();

//... require() route files

file route / 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
źródło
6
Uwaga: generalnie lepiej jest wyraźnie mówić o przekazywaniu zmiennych i tworzeniu ich instancji, aby przypadkowo nie zerwać referencji w innym miejscu aplikacji lub co masz.
Paul,
3
To naprawdę zła forma, jak zauważył Paul. Proponuję poniższy wzór wtrysku. Tak, więcej kocowego kodu, więc nie wygląda "ładnie", ale zapewnia, że ​​twój kod jest modułowy ... coś, co ci się spodoba, jeśli to nie jest twój ostatni projekt;)
srquinn
To zależy od okoliczności IMHO. Tak, globalne zmienne generalnie nie są dobrą praktyką (jak powiedziałem w mojej odpowiedzi) i zaczynając od zera, powiedziałbym, że zorganizuj wszystko w oddzielne moduły. Ale jeśli integrujesz się z istniejącym kodem, często istnieją inne kwestie - tak się składa, że ​​jest to jedno (łatwe, ale niebezpieczne) rozwiązanie.
Jesse Fulton,
2
Czy ktoś mógłby wyjaśnić, dlaczego to działa w odniesieniu do semantyki Javascript? Z którym zakresem jest apppowiązany?
Ali
Nie sądzę, aby ta odpowiedź oznaczała jako correctjedną.
Code Cooker
93

W rzeczywistości jest to bardzo łatwe przy użyciu metod „set” i „get” dostępnych w obiekcie ekspresowym.

Przykład poniżej, powiedzmy, że masz zmienną o nazwie config z elementami związanymi z konfiguracją, które chcesz, aby były dostępne w innych miejscach:

W app.js:

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

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

W route / index.js

exports.index = function(req, res){
  var config = req.app.get('config');
  // config is now available
  ...
}
Mandy
źródło
Ustawić „aplikację” jako globalną? Tak. Ale ta metoda jest najlepsza, aby uchronić nas przed problemami i chaosem.
diproart
53
dla spóźnialskich: app.configure zostanie usunięta w express 4.x
zamil
Fajnie, req.app.get('name')działa jak urok. Ta właściwość zawiera odwołanie do wystąpienia aplikacji Express, która używa oprogramowania pośredniego. expressjs.com/pt-br/api.html#req.app
Lazaro Fernandes Lima Suleiman
58

Sprytnym sposobem na to jest użycie app.localssamego Expressu. Oto dokumentacja.

// 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;
}
Ali
źródło
1
Użyłem tej metody do zlokalizowania usług http i łatwego nadpisywania w testach jednostkowych.
Alex
28

Aby zadeklarować zmienną globalną, musisz użyć obiektu globalnego . Na przykład global.yourVariableName. Ale to nie jest prawdziwa droga. Aby udostępniać zmienne między modułami, spróbuj użyć stylu wtrysku, takiego jak

someModule.js:

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

app.js

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

Lub możesz do tego użyć obiektu zastępczego. Jak 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
źródło
7

Oto krótkie wyjaśnienie:

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

Więc pracujesz z zestawem modułów Node, być może frameworkiem takim jak Express.js, i nagle czujesz potrzebę uczynienia niektórych zmiennych globalnymi. Jak sprawić, by zmienne były globalne w Node.js?

Najczęstszą radą w tym przypadku jest „zadeklarowanie zmiennej bez słowa kluczowego var”, „dodanie zmiennej do obiektu globalnego” lub „dodanie zmiennej do obiektu GLOBAL”. Którego używasz?

Po pierwsze, przeanalizujmy obiekt globalny. Otwórz terminal, uruchom Node REPL (zachęta).

> 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
źródło
W Expressie - gdy używasz jshint lub ogólnie lintingu - staje się to problemem.
Steven Ventimiglia
6

Najłatwiejszym sposobem jest wczesne zadeklarowanie zmiennej globalnej w pliku app.js:

global.mySpecialVariable = "something"

wtedy na dowolnych trasach możesz to zdobyć:

console.log(mySpecialVariable)
Szaman
źródło
1
W Expressie - gdy używasz jshint lub ogólnie lintingu - staje się to problemem.
Steven Ventimiglia
5

Było to pomocne pytanie, ale mogłoby być bardziej przydatne, podając rzeczywiste przykłady kodu. Nawet linkowany artykuł w rzeczywistości nie pokazuje implementacji. Dlatego pokornie poddaję:

W app.jspliku początek pliku:

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 nie będzie mieć żadnego odniesienia do app.get()metody. Pozostaw to do zdefiniowania w poszczególnych plikach tras.

routes/index.js:

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

i na koniec rzeczywisty plik tras 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
źródło
4

Moim preferowanym sposobem jest użycie zależności cyklicznych *, które obsługuje węzeł

  • w app.js zdefiniuj var app = module.exports = express();jako pierwsze zamówienie biznesowe
  • Teraz każdy moduł wymagany po fakcie może var app = require('./app')uzyskać do niego dostęp


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


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');
Will Stern
źródło
Świetna wskazówka. Po prostu przeszedłem od metody require ('./ myroutes') (aplikacja) do zrobienia tego i uderzyłem głową o ścianę przez 10 minut, próbując dowiedzieć się, dlaczego żadna z moich tras nie zadziałała. Nie zapomnij pobrać specyfikacji tras w myroutes.js z bloku funkcyjnego. No!
greg
2

Jak inni już udostępnili, app.set('config', config)jest do tego świetny. Chciałem tylko dodać coś, czego nie widziałem w istniejących odpowiedziach, co jest dość ważne. Instancja Node.js jest współużytkowana we wszystkich żądaniach, więc chociaż może być bardzo praktyczne udostępnianie części configlub routerobiektów globalnie, globalne przechowywanie danych wykonawczych będzie dostępne dla żądań i użytkowników . Rozważmy ten bardzo prosty przykład:

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

Jeśli odwiedzisz stronę /bari trafi kolejna prośba /foo, Twoja wiadomość będzie brzmiała „Witamy w foo!”. To głupi przykład, ale trafia w sedno.

Jest kilka interesujących punktów na ten temat w Dlaczego różne sesje node.js współużytkują zmienne? .

Charlie Schliesser
źródło
1

Rozwiązałem ten sam problem, ale musiałem napisać więcej kodu. Stworzyłem server.jsplik, który używa express do rejestracji tras. Udostępnia funkcję, registerktóra może być używana przez inne moduły do ​​rejestrowania własnych tras. Udostępnia również funkcję startServer, aby rozpocząć nasłuchiwanie portu

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
}

W innym module użyj tego pliku, aby utworzyć trasę.

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
}

W głównym pliku załaduj oba.

app.js

require('./server').startServer(7000)
require('./web/help').registerHelp()
Amar Dev
źródło
0

Odpowiedź Johna Gordona była pierwszą z kilkudziesięciu częściowo wyjaśnionych / udokumentowanych odpowiedzi, które wypróbowałem, z wielu, wielu witryn, które faktycznie zadziałały. Dziękuję panie Gordon. Przepraszam, że nie mam punktów, aby poprawić Twoją odpowiedź.

Chciałbym dodać, że dla innych początkujących użytkowników dzielenia węzłów trasy-plików, użycie funkcji anonimowej dla `` indeksu '' jest tym, co będzie częściej widziane, więc używając przykładu Johna dla main.js, funkcjonalnie- równoważny kod, który normalnie można znaleźć, to:

app.get('/',(req, res) {
    res.render('index', { title: 'Express' });
});
JosephK
źródło
0

Użyłem app.all

Metoda app.all () jest przydatna do mapowania logiki „globalnej” dla określonych prefiksów ścieżek lub dowolnych dopasowań.

W moim przypadku używam confit do zarządzania konfiguracją,

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

Na trasach po prostu to robisz req.app.get('config').get('cookie');

nilesh
źródło
0

jest to całkiem prosta rzecz, ale odpowiedzi ludzi są jednocześnie zagmatwane i złożone.

pokażę ci, jak możesz ustawić zmienną globalną w swojej expressaplikacji. W razie potrzeby możesz uzyskać do niego dostęp z dowolnej trasy.

Powiedzmy, że chcesz ustawić zmienną globalną z głównej /trasy

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

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

Będziesz więc otrzymywać wymaganą aplikację ze wszystkich tras. a następnie będziesz musiał użyć, localsaby ustawić dane globalne w. jak powyżej, pokaż, że wszystko gotowe teraz pokażę ci, jak korzystać z tych danych

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

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

Podobnie jak powyżej z registertrasy, do której uzyskujesz dostęp, dane zostały ustawione wcześniej.

W ten sposób możesz sprawić, by to działało!

Code Cooker
źródło