如何在nodeJs vm中使用readFileSync

时间:2015-03-31 16:46:27

标签: node.js

我正在尝试使用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的本地上下文?

3 个答案:

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