日期: 2020-06-22 17:51:58
本文实例讲述了Node.js API详解之 vm模块用法。分享给大家供大家参考,具体如下:
Node.js API详解之 vm
vm 模块提供了一系列 API 用于在 V8 虚拟机环境中编译和运行代码。
JavaScript 代码可以被编译并立即运行,或编译、保存然后再运行。
常见的用法是在沙盒中运行代码。沙盒代码使用不同的V8上下文。
const vm = require('vm'); const x = 1; const sandbox = { x: 2 }; vm.createContext(sandbox); // Contextify the sandbox. const code = 'x += 40; var y = 17;'; // x and y are global variables in the sandboxed environment. // Initially, x has the value 2 because that is the value of sandbox.x. vm.runInContext(code, sandbox); console.log(sandbox.x); // 42 console.log(sandbox.y); // 17 console.log(x); // 1; y is not defined.
注意: vm模块并不是实现代码安全性的一套机制。 绝不要试图用其运行未经信任的代码.
说明:
vm.createContext()主要是用于创建一个能运行多个脚本的sandbox。
比如说,在模拟一个网页浏览器时,此方法可以被用于创建一个单独的sandbox来代表一个窗口的全局对象,然后所有的script标签都可以在这个sandbox的上下文中运行。
给定一个sandbox对象, vm.createContext()会设置此sandbox,
从而让它具备在vm.runInContext()或者script.runInContext()中被使用的能力。
如果未提供sandbox(或者传入undefined),那么会返回一个全新的,空的,上下文隔离化后的sandbox对象。
对于此方法中所调用的脚本,他们的全局对象不仅拥有我们提供的sandbox对象的所有属性,同时还有任何global object所拥有的属性。
对于这些脚本之外的所有代码,他们的全局变量将保持不变。
demo:
const util = require('util'); const vm = require('vm'); global.globalVar = 3; const sandbox = { globalVar: 1 }; vm.createContext(sandbox); vm.runInContext('globalVar *= 2;', sandbox); console.log(util.inspect(sandbox)); // { globalVar: 2 } console.log(util.inspect(globalVar)); // 3
说明:
当给定的sandbox对象已经被vm.createContext()上下文隔离化,则返回真。
demo:
const util = require('util'); const vm = require('vm'); global.globalVar = 3; const sandbox = { globalVar: 1 }; vm.createContext(sandbox); console.log(vm.isContext(sandbox)); // true
说明:
code:将被编译和运行的JavaScript代码
contextifiedSandbox:一个被上下文隔离化过的对象,会在代码被编译和执行之后充当global对象
options:
filename:定义供脚本生成的堆栈跟踪信息所使用的文件名
lineOffset:定义脚本生成的堆栈跟踪信息所显示的行号偏移
columnOffset:定义脚本生成的堆栈跟踪信息所显示的列号偏移
displayErrors:当值为真的时候,假如在解析代码的时候发生错误Error,引起错误的行将会被加入堆栈跟踪信息
timeout:定义在被终止执行之前此code被允许执行的最大毫秒数。假如执行被终止,将会抛出一个错误Error
vm.runInContext()在指定的contextifiedSandbox的上下文里执行vm.Script对象中被编译后的代码并返回其结果。
被执行的代码无法获取本地作用域。contextifiedSandbox必须是事先被vm.createContext()上下文隔离化过的对象。
demo:
const util = require('util'); const vm = require('vm'); global.globalVar = 3; const sandbox = { globalVar: 1 }; vm.createContext(sandbox); vm.runInContext('globalVar *= 2;', sandbox); console.log(util.inspect(sandbox)); // { globalVar: 2 }
说明:
vm.runInDebugContext()会在V8的调试上下文中编译并执行code。此方法主要在需要获取V8Debug对象的时候使用。
注意: 调试上下文和对象从本质而言是从属于V8调试器的,故有可能会在没有事先警告的情况下被改变(甚至被移除)
Debug对象另外还可以通过特定于V8的–expose_debug_as命令行选项获得。
demo:
const vm = require('vm') const Debug = vm.runInDebugContext('Debug'); console.log(Debug.findScript(process.emit).name); // 'events.js' console.log(Debug.findScript(process.exit).name); // 'internal/process.js'
说明:
首先给指定的sandbox(若为undefined,则会新建一个sandbox)提供一个隔离的上下文,
再在此上下文中执行vm.Script中被编译的代码,最后返回结果。运行中的代码无法获取本地作用域。
demo:
const util = require('util'); const vm = require('vm'); const sandbox = { animal: 'cat', count: 2 }; vm.runInNewContext('count += 1; name = "kitty"', sandbox); console.log(util.inspect(sandbox)); // { animal: 'cat', count: 3, name: 'kitty' }
说明:
vm.runInThisContext()在当前的global对象的上下文中编译并执行code,最后返回结果。
运行中的代码无法获取本地作用域,但可以获取当前的global对象。
demo:
const vm = require('vm'); let localVar = 'initial value'; const vmResult = vm.runInThisContext('localVar = "vm";'); console.log('vmResult:', vmResult); console.log('localVar:', localVar); const evalResult = eval('localVar = "eval";'); console.log('evalResult:', evalResult); console.log('localVar:', localVar); // vmResult: 'vm', localVar: 'initial value' // evalResult: 'eval', localVar: 'eval'
说明:
vm.Script类型的实例包含若干预编译的脚本,这些脚本能够在特定的沙箱(或者上下文)中被运行。
说明:
创建一个新的vm.Script对象只编译代码但不会执行它。编译过的vm.Script此后可以被多次执行。
值得注意的是,code是不绑定于任何全局对象的,相反,它仅仅绑定于每次执行它的对象。
code:要被解析的JavaScript代码
options:
filename:定义供脚本生成的堆栈跟踪信息所使用的文件名
lineOffset:定义脚本生成的堆栈跟踪信息所显示的行号偏移
columnOffset:定义脚本生成的堆栈跟踪信息所显示的列号偏移
displayErrors:当值为真的时候,假如在解析代码的时候发生错误Error,引起错误的行将会被加入堆栈跟踪信息
timeout:定义在被终止执行之前此code被允许执行的最大毫秒数。假如执行被终止,将会抛出一个错误[Error][]。
cachedData:为源码提供一个可选的存有v8代码缓存数据的Buffer。一旦提供了此Buffer,取决于v8引擎对Buffer中数据的接受状况,cachedDataRejected值将会被设为要么 真要么为假。
produceCachedData:当值为真且cachedData不存在的时候,v8将会试图为code生成代码缓存数据。一旦成功,一个有V8代码缓存数据的Buffer将会被生成和储存在vm.Script返回的实例的cachedData属性里。 取决于代码缓存数据是否被成功生成,cachedDataProduced的值会被设置为true或者false。
demo:
const util = require('util'); const vm = require('vm'); const sandbox = { animal: 'cat', count: 2 }; const script = new vm.Script('count += 1; name = "kitty";'); const context = vm.createContext(sandbox); script.runInContext(context); console.log(util.inspect(sandbox)); // { animal: 'cat', count: 3, name: 'kitty' }
说明:
在指定的contextifiedSandbox中执行vm.Script对象中被编译后的代码并返回其结果。
被执行的代码无法获取本地作用域。
contextifiedSandbox:由vm.createContext()返回的[contextified][]对象
demo:
const util = require('util'); const vm = require('vm'); const sandbox = { animal: 'cat', count: 2 }; const script = new vm.Script('count += 1; name = "kitty";'); const context = vm.createContext(sandbox); for (let i = 0; i < 10; ++i) { script.runInContext(context); } console.log(util.inspect(sandbox)); // { animal: 'cat', count: 12, name: 'kitty' }
说明:
首先给指定的sandbox提供一个隔离的上下文, 再在此上下文中执行vm.Script中被编译的代码,最后返回结果。
运行中的代码无法获取本地作用域。
demo:
const util = require('util'); const vm = require('vm'); const script = new vm.Script('globalVar = "set"'); const sandboxes = [{}, {}, {}]; sandboxes.forEach((sandbox) => { script.runInNewContext(sandbox); }); console.log(util.inspect(sandboxes)); // [{ globalVar: 'set' }, { globalVar: 'set' }, { globalVar: 'set' }]
说明:
在指定的global对象的上下文中执行vm.Script对象里被编译的代码并返回其结果。
被执行的代码虽然无法获取本地作用域,但是能获取global对象。
demo:
const vm = require('vm'); global.globalVar = 0; const script = new vm.Script('globalVar += 1'); for (let i = 0; i < 1000; ++i) { script.runInThisContext(); } console.log(globalVar); // 1000
'use strict'; const vm = require('vm'); const code = ` (function(require) { const http = require('http'); http.createServer((request, response) => { response.writeHead(200, { 'Content-Type': 'text/plain' }); response.end('Hello World\\n'); }).listen(8124); console.log('Server running at http://127.0.0.1:8124/'); })`; vm.runInThisContext(code)(require);
希望本文所述对大家node.js程序设计有所帮助。