Global Variable ใน app.js สามารถเข้าถึงได้ในเส้นทาง?


93

ฉันจะตั้งค่าตัวแปรapp.jsและให้มันพร้อมใช้งานในทุกเส้นทางอย่างน้อยที่สุดในindex.jsไฟล์ที่อยู่ในเส้นทางได้อย่างไร โดยใช้กรอบงานด่วนและnode.js


1
app.localsวัตถุมีคุณสมบัติที่มีตัวแปรท้องถิ่นภายในโปรแกรม ในไฟล์เส้นทางของคุณอ้างอิงด้วยreq.app.locals.
Ronnie Royston

คำตอบ:


67

ในการสร้างตัวแปรส่วนกลางเพียงแค่ประกาศโดยไม่มี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

เส้นทางไฟล์/ 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

ขึ้นอยู่กับสถานการณ์ IMHO ใช่โดยทั่วไปตัวแทนทั่วโลกไม่ใช่แนวทางปฏิบัติที่ดี (ตามที่ฉันระบุไว้ในคำตอบของฉัน) และเมื่อเริ่มต้นใหม่ฉันจะบอกว่าจัดระเบียบทุกอย่างเป็นโมดูลแยกต่างหาก แต่ถ้าคุณผสานรวมกับโค้ดที่มีอยู่มักจะมีข้อควรพิจารณาอื่น ๆ ซึ่งเป็นวิธีแก้ปัญหา (ง่าย แต่อันตราย)
Jesse Fulton

2
มีใครช่วยอธิบายได้ไหมว่าเหตุใดจึงใช้งานได้โดยอ้างอิงความหมายของ Javascript ขอบเขตใดที่appเกี่ยวข้องกับ?
Ali

ฉันไม่คิดว่าคำตอบนี้ควรทำเครื่องหมายเป็นcorrectหนึ่ง
Code Cooker

96

ที่จริงแล้วทำได้ง่ายมากโดยใช้เมธอด "set" และ "get" ที่มีอยู่ในอ็อบเจกต์ด่วน

ตัวอย่างดังนี้สมมติว่าคุณมีตัวแปรที่เรียกว่า config พร้อมกับสิ่งที่เกี่ยวข้องกับคอนฟิกูเรชันของคุณที่คุณต้องการให้มีในที่อื่น

ใน app.js:

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

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

ในเส้นทาง / index.js

exports.index = function(req, res){
  var config = req.app.get('config');
  // config is now available
  ...
}

ตั้งค่า "แอป" ทั่วโลกหรือไม่ ใช่. แต่วิธีนี้ดีที่สุดสำหรับช่วยเราในเรื่องปัญหาและความวุ่นวาย
diproart

55
สำหรับผู้มาสาย: app.configure จะถูกลบออกใน express 4.x
zamil

ดีreq.app.get('name')ใช้ได้เหมือนมีเสน่ห์ คุณสมบัตินี้มีการอ้างอิงถึงอินสแตนซ์ของแอ็พพลิเคชัน Express ที่ใช้มิดเดิลแวร์ expressjs.com/pt-br/api.html#req.app
Lazaro Fernandes Lima Suleiman

61

วิธีที่เป็นระเบียบคือการใช้app.localsExpress เอง นี่คือเอกสาร

// 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 object เช่น 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

ดังนั้นคุณกำลังทำงานกับชุดของโมดูลโหนดซึ่งอาจจะเป็นเฟรมเวิร์กเช่น Express.js และทันใดนั้นเองก็รู้สึกว่าจำเป็นต้องสร้างตัวแปรให้เป็นสากล คุณสร้างตัวแปรทั่วโลกใน Node.js ได้อย่างไร

คำแนะนำที่พบบ่อยที่สุดสำหรับข้อนี้คือ "ประกาศตัวแปรโดยไม่มีคีย์เวิร์ด var" หรือ "เพิ่มตัวแปรให้กับ global object" หรือ "add the variable to the GLOBAL object" คุณใช้อันไหน?

ก่อนอื่นเรามาวิเคราะห์วัตถุระดับโลกกันก่อน เปิดเทอร์มินัลเริ่ม 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 หรือ linting โดยทั่วไปจะกลายเป็นปัญหา
Steven Ventimiglia

7

วิธีที่ง่ายที่สุดคือการประกาศตัวแปรส่วนกลางใน app.js ของคุณในช่วงต้น:

global.mySpecialVariable = "something"

จากนั้นในเส้นทางใดก็ได้ที่คุณจะได้รับ:

console.log(mySpecialVariable)

1
ใน Express - เมื่อใช้ jshint หรือ linting โดยทั่วไปจะกลายเป็นปัญหา
Steven Ventimiglia

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

เคล็ดลับที่ดี ฉันเพิ่งย้ายจากวิธีการที่ต้องการ ('./ 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ไฟล์ที่ใช้ Express เพื่อลงทะเบียนเส้นทาง มันแสดงฟังก์ชัน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()

1

นี่เป็นสิ่งที่ค่อนข้างง่าย แต่คำตอบของผู้คนนั้นสับสนและซับซ้อนในเวลาเดียวกัน

ให้ฉันแสดงวิธีตั้งค่าตัวแปรส่วนกลางในไฟล์ 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เส้นทางที่คุณเข้าถึงข้อมูลได้รับการตั้งค่าไว้ก่อนหน้านี้

นี่คือวิธีที่คุณจะทำให้สิ่งนี้ทำงานได้!


0

คำตอบของจอห์นกอร์ดอนเป็นคำตอบแรกจากคำตอบที่อธิบาย / บันทึกไว้ครึ่งหนึ่งหลายสิบฉบับที่ฉันได้ลองจากหลาย ๆ ไซต์ที่ใช้งานได้จริง ขอบคุณนายกอร์ดอน ขออภัยฉันไม่มีคะแนนที่จะเลือกคำตอบของคุณ

ฉันต้องการเพิ่มสำหรับมือใหม่คนอื่น ๆ ในการแยกโหนดเส้นทาง - ไฟล์ว่าการใช้ฟังก์ชันไม่ระบุชื่อสำหรับ 'ดัชนี' เป็นสิ่งที่จะเห็นบ่อยขึ้นดังนั้นการใช้ตัวอย่างของ John สำหรับ main.js ซึ่งเป็นฟังก์ชัน - รหัสที่เทียบเท่ากันโดยปกติจะพบคือ:

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

0

ฉันใช้app.all

เมธอด app.all () มีประโยชน์สำหรับการแมปลอจิก "global" สำหรับคำนำหน้าพา ธ เฉพาะหรือการจับคู่โดยพลการ

ในกรณีของฉันฉันใช้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');

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.