【问题标题】:Run js code in a separate context and access its global variable在单独的上下文中运行 js 代码并访问其全局变量
【发布时间】:2016-04-26 10:11:42
【问题描述】:

我想在 node 中运行第三方 JavaScript 文件(我对其内容没有太多控制权)并访问由该文件的代码在其上下文中创建的全局变量。

我考虑过两件事:

  1. vm 沙箱中运行代码。问题是我不知道如何正确创建上下文,因为vm.createContext([sandbox]) 不会自动为我想要的脚本提供consolerequire 等基本内容运行。

    这有点令人失望,因为文档明确指出(强调我的):

    如果给定沙箱对象,将“上下文化”该沙箱,以便在调用 vm.runInContext() 或 script.runInContext() 时使用它。在这样运行的脚本内部,沙箱将成为全局对象,保留其所有现有属性但也具有任何标准全局对象所具有的内置对象和功能

    什么是“任何标准全局对象所具有的内置对象和函数”?我天真地假设它是consoleprocessrequire 等。但如果是这样,API 就不起作用,因为这些都没有设置。我可能在这里误解了一些东西。

    var sandbox = vm.createContext({foo: 'foo'});
    var code = 'console.log(foo);';
    vm.runInContext(code, sandbox);
    

    结果:

    evalmachine.:1
    控制台.log(foo);
    ^
    ReferenceError: 未定义控制台

  2. child process 中运行代码。但我找不到任何有关访问子进程全局变量的文档。我假设与子进程通信的唯一方法是通过消息传递,但即使这样似乎也是从父进程到子进程,而不是相反...

基本上,我被困住了。停下来。

【问题讨论】:

  • @dandavis 任何类型(可序列化)。
  • child_process.exec(command[, options][, callback]) 的回调将输出提供给 stdOut 缓冲区,因此如果您的子进程 console.logs(strJSON),您可以在回调中取回它。其他的好方法很复杂,但是你可以很简单地使用 HTTP 或临时文件来完成一些任务......“IPC”
  • @dandavis 我已经考虑过了,但是代码可能会自己记录日志,我宁愿不干涉。

标签: javascript node.js


【解决方案1】:

您可以使用advanced vm/sandbox for Node.js

var VM = require('vm2').NodeVM; // https://github.com/patriksimek/vm2#nodevm

var options = {
    console: 'inherit',
    sandbox: {
        foo: 'foo'
    }
}

vm = new VM(options);

var code = `
    console.log(foo); 
    oldFoo = foo; 
    foo = Math.random();
`;

vm.run(code);

console.log(vm.context.oldFoo, vm.context.foo);

【讨论】:

  • 看起来很整洁,效果很好,+1。虽然有边缘情况问题。例如,我注意到process.exit 没有处理程序。
  • 此类情况可以使用try { vm.run } catch(e) {}回复吗?
【解决方案2】:

在上下文中传递父级的console 怎么样?

const vm = require('vm');

var sandbox = {
  console: console
};

var context = new vm.createContext(sandbox);
var script = new vm.Script('console.log("foo")');

script.runInContext(context);

【讨论】:

  • 我已经考虑过了,问题是正在运行的代码可能需要其他东西,比如requireprocess__dirname...我不可能可靠地列出他们都。
  • 我假设您不想让不受信任的代码访问这些符号。如果这样做,只需将global 传递为sandbox
【解决方案3】:

在这段代码中,我们可以发送任何响应,并且可以使用全局函数访问全局变量,并且可以访问从 VM Sandbox 返回的全部数据。

 function compiler(){
     let add = x*y
     Return (add);
 }
 compiler();

const vm = new NodeVM({
   sandbox: {
     Return(data) {
       console.log('Data:', data);
     },
     x : 10,=
     y : 20
   },
   require: {
     external: true,
     builtin: ["fs", "path"],
     root: "./",
     mock: {
       fs: {
         readFileSync() {
           return "Nice try!";
         }
       }
     }
   }
 });
 try {
   vm.run(req.query.code);
 } catch (error) {
   console.log("error: ", error);
 }

【讨论】:

  • 你能解释一下:Return (data) {...} 工作,你能提供API吗?不太确定这是有效的 JS 语法
  • 名为sandbox的参数只是和sandbox环境中的变量和函数的声明有关...
  • 你可以简单地命名它任何你想要的名字。它的沙盒函数我们可以在我们的代码中随时调用。
  • 这有助于通过调用它来完成复杂的任务。
猜你喜欢
  • 2023-02-17
  • 2012-05-25
  • 2018-06-01
  • 2019-05-27
  • 1970-01-01
  • 1970-01-01
  • 2020-06-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多