2015-03-31 38 views
6

我正在試用nodeJs vm。此代碼的工作:如何在nodeJs中使用readFileSync vm

server.js

var fs = require('fs'); 
    var vm = require('vm'); 

    var app = fs.readFileSync(__dirname + '/' + 'app.js'); 
    vm.runInThisContext(app); 


    var http = require('http'); 

    var server = http.createServer(onRequest); 
    server.listen(8080, '127.0.0.1'); 

app.js

function onRequest(req, res) { 
     res.writeHead(200, {'Content-Type': 'text/html'}); 
     res.end('Hello Node.js\n'); 
    } 

現在,如果我改變app.js到

function onRequest(req, res) { 
     res.writeHead(200, {'Content-Type': 'text/html'}); 
     res.end(fs.readFileSync(__dirname + '/index.html')); 
    } 

它不工作了:瀏覽器將打印「此網頁不可用」

如何使它工作可能以某種方式將fs.readFileSync綁定到onRequest的本地上下文?

回答

1

docs報價:

運行的代碼不能訪問本地範圍,但有機會獲得當前全球對象。

因此,變量__dirname和模塊fs在該上下文中是undefined

爲了解決這個問題,使用global對象:

server.js

var fs = require('fs'); 
var vm = require('vm'); 

global.fs = fs; 
global.__dirname = __dirname; 

var app = fs.readFileSync(__dirname + '/' + 'app.js'); 
vm.runInThisContext(app); 


var http = require('http'); 

var server = http.createServer(onRequest); 
server.listen(8080, '127.0.0.1'); 

app.js

function onRequest(req, res) { 
    res.writeHead(200, {'Content-Type': 'text/html'}); 
    res.end(global.fs.readFileSync(global.__dirname + '/index.html')); 
} 
+1

運行app.js哇,謝謝我徘徊在谷歌和C無法找到答案:) – user310291 2015-04-04 12:46:57

2

雖然張貼JohnKiller答案是技術上是正確的,我會喜歡指出一個使用vm.runInContext的解決方案,並且在我看來更強大。

// app.js 
var fs = require('fs'); 
module.exports = function onRequest(req, res) { 
    res.writeHead(200, {'Content-Type': 'text/html'}); 
    res.end(fs.readFileSync(__dirname + '/index.html')); 
} 

// server.js 
var appFile = __dirname + '/' + 'app.js'; 
var app = fs.readFileSync(appFile); 

var context = vm.createContext({ 
    __filename: appFile, 
    __dirname: __dirname, 
    require: require, 
    module: { exports: {} } 
}); 
context.exports = context.module.exports; 

vm.runInContext(app, context, { filename: appFile }); 
var onRequest = context.module.exports; 

var http = require('http'); 
var server = http.createServer(onRequest); 
server.listen(8080, '127.0.0.1'); 

我看到以下幾大好處:

1)全球範圍內沒有與僅通過加載腳本文件中使用額外的變量污染。

2)從外部文件加載的代碼被沙箱化,它不能直接更改調用者的作用域變量。非常清楚外部文件可用的變量。

3)外部文件中的代碼是自封裝的,不依賴於上下文中提供的任何外部模塊。實際上,它是一個常規的Node.js文件,可以通過require('./app.js')

1

wtf直接加載,爲什麼?

var app = fs.readFileSync(__dirname + '/' + 'app.js'); 
vm.runInThisContext(app); 

只是做:

require('./app.js') 

的sooo你整個應用程序看起來像:

server.js

var http = require('http'); 
// use './' for relative paths 
var app = require('./app.js'); 
// load app.js 
var server = http.createServer(app); 
server.listen(8080, '127.0.0.1'); 

app.js

// app.js has to load `fs` for itself 
var fs = require('fs'); 
module.exports = function app(req, res) { 
    res.writeHead(200, {'Content-Type': 'text/html'}); 
    res.end(global.fs.readFileSync('./index.html')); 
} 

完成

但是,如果由於某種原因,你真的想讀,編譯和代替vm簡單的老require

server.js

var http = require('http'); 
// use './' for relative paths 
var app = vm.runInThisContext('./app.js'); 
// load app.js 
var server = http.createServer(app); 
server.listen(8080, '127.0.0.1'); 

app.js

// app.js _still_ has to load `fs` for itself 
var fs = require('fs'); 

// last value is returned 
function app(req, res) { 
    res.writeHead(200, {'Content-Type': 'text/html'}); 
    res.end(global.fs.readFileSync('./index.html')); 
}