我正在尝试使用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的本地上下文?
答案 0 :(得分: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 :(得分: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'));
}
答案 2 :(得分:1)
wtf,为什么?
var app = fs.readFileSync(__dirname + '/' + 'app.js');
vm.runInThisContext(app);
只是这样做:
require('./app.js')
所以整个应用程序看起来像是:
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'));
}