如何在nodeJs vm中使用readFileSync

我正在试验nodeJs 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的本地上下文?

从文档引用:

运行代码无权访问本地作用域,但可以访问当前全局对象。

所以,variables__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')); } 

尽pipeJohnKiller发布的答案在技术上是正确的,但我想指出一个使用vm.runInContext的解决scheme,并且在我看来更加健壮。

 // 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)全局上下文不受仅由加载的脚本文件使用的附加variables的污染。

2)从外部文件加载的代码被沙箱化,不能直接改变调用者的作用域variables。 非常清楚外部文件可用的variables。

3)外部文件中的代码是自封装的,不依赖于上下文中提供的任何外部模块。 实际上,它是一个常规的Node.js文件,可以通过require('./app.js')直接加载

跆拳道,为什么?

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

完成

但是,如果由于某种原因,你真的想读取,编译和运行app.jsvm而不是简单的旧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')); }