如何在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.js
与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')); }