Python 调用 Node.js(vm2 沙箱)完美方案:胶水层实战教程

你要的是 Python 作为主语言,调用 Node.js 里的 vm2 沙箱执行不安全 JS 代码,用 ** 胶水层(胶水语言 / 跨语言通信)** 实现,我给你两套最实用、可直接上线的方案:

核心需求

  1. Python 调用 JS
  2. JS 内部用 vm2 安全沙箱 执行不可信代码
  3. 跨语言通信(胶水)
  4. 完整可运行代码

我直接给你 最稳定、生产可用 的两套方案:

  • 方案 A(最简单):Python 子进程调用 Node.js 脚本(推荐新手)
  • 方案 B(高性能):Python + Node.js 双向 RPC 通信(适合频繁调用)

先准备环境

1. 创建项目

bash

运行

复制代码
mkdir python-vm2
cd python-vm2

2. 安装依赖

bash

运行

复制代码
# 安装 vm2
npm init -y
npm install vm2

# Python 无需额外安装库(内置 subprocess)

方案 A:最简胶水方案(Python 子进程调用 Node)

原理:Python 启动一个 Node 子进程,把代码传给 Node,Node 用 vm2 执行后把结果返回给 Python。最简单、最安全、无依赖。

1. 新建 Node 胶水脚本:runner.js

javascript

运行

复制代码
const { VM } = require('vm2');

// 从命令行接收 Python 传过来的 JS 代码
const userCode = process.argv[2] || '';

try {
    // 创建安全沙箱
    const vm = new VM({
        timeout: 1000,
        allowAsync: false,
        sandbox: {
            // 你可以给沙箱开放安全变量
            PI: 3.14159
        }
    });

    // 执行代码
    const result = vm.run(userCode);
    
    // 返回结果给 Python
    console.log(JSON.stringify({ success: true, data: result }));

} catch (err) {
    // 错误返回
    console.log(JSON.stringify({ success: false, error: err.message }));
}

2. 新建 Python 调用脚本:main.py

python

运行

复制代码
import subprocess
import json
import sys

def run_js_in_vm2(js_code: str):
    """
    Python 胶水函数:调用 Node.js + vm2 执行不安全 JS 代码
    """
    try:
        # 调用 node runner.js "代码"
        result = subprocess.run(
            [sys.executable.replace("python", "node"), "runner.js", js_code],
            capture_output=True,
            text=True,
            encoding="utf-8",
            timeout=3
        )

        # 解析返回结果
        output = result.stdout.strip()
        return json.loads(output)

    except Exception as e:
        return {"success": False, "error": str(e)}

# ====================== 测试 ======================
if __name__ == "__main__":
    # 测试 1:安全代码
    code1 = "1 + 2 * 3 + PI"
    print("执行结果:", run_js_in_vm2(code1))

    # 测试 2:沙箱禁止的危险代码(会被拦截)
    code2 = "process.exit()"
    print("危险代码执行:", run_js_in_vm2(code2))

3. 运行

bash

运行

复制代码
python main.py

输出结果

plaintext

复制代码
执行结果: {'success': True, 'data': 10.14159}
危险代码执行: {'success': False, 'error': 'ReferenceError: process is not defined'}

完美实现 Python 调用 vm2 沙箱


方案 B:高性能胶水方案(长连接 RPC)

适合你频繁调用 JS 沙箱的场景(比如批量执行、在线编辑器)。

使用 stdout/stdin 双向通信,Node 保持运行,Python 持续发指令。

1. Node 服务端:rpc_server.js

javascript

运行

复制代码
const { VM } = require('vm2');
const readline = require('readline');

// 创建沙箱
const vm = new VM({
    timeout: 1000,
    allowAsync: true,
    sandbox: { PI: 3.14159 }
});

// 读取 Python 传来的消息
const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout
});

console.log("VM2 RPC 服务已启动");

rl.on('line', (code) => {
    try {
        const res = vm.run(code);
        console.log(`[RESULT]${JSON.stringify(res)}`);
    } catch (err) {
        console.log(`[ERROR]${err.message}`);
    }
});

2. Python 客户端:rpc_client.py

python

运行

复制代码
import subprocess
import threading
import json

class VM2Client:
    def __init__(self):
        # 启动 Node 服务
        self.proc = subprocess.Popen(
            ["node", "rpc_server.js"],
            stdin=subprocess.PIPE,
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
            text=True,
            encoding="utf-8"
        )
        self.response = None

    def _read_output(self):
        while True:
            line = self.proc.stdout.readline()
            if not line:
                break
            self.response = line.strip()

    def run(self, code):
        # 启动监听线程
        threading.Thread(target=self._read_output, daemon=True).start()
        
        # 发送代码
        self.proc.stdin.write(code + "\n")
        self.proc.stdin.flush()
        
        # 等待返回
        while self.response is None:
            pass
        
        res = self.response
        self.response = None
        return res

# ====================== 测试 ======================
if __name__ == "__main__":
    client = VM2Client()

    print(client.run("100 + 200"))
    print(client.run("PI * 2"))
    print(client.run("process"))  # 被沙箱禁止

运行

bash

运行

复制代码
python rpc_client.py

你可以直接使用的【生产级安全沙箱胶水代码】

我给你整合一个 最实用、最安全、直接复制就能用 的版本:

safe_runner.js

javascript

运行

复制代码
const { NodeVM } = require('vm2');
const code = process.argv[2];

const vm = new NodeVM({
    timeout: 1500,
    eval: false,
    wasm: false,
    console: 'off',
    require: {
        builtin: [],
        external: false,
        deny: ['*']
    }
});

try {
    const result = vm.run(code);
    console.log(JSON.stringify({ ok: 1, data: result }));
} catch (e) {
    console.log(JSON.stringify({ ok: 0, err: e.message }));
}

Python 调用胶水函数

python

运行

复制代码
import subprocess
import json

def js_sandbox(js_code: str):
    res = subprocess.run(
        ["node", "safe_runner.js", js_code],
        capture_output=True,
        text=True
    )
    return json.loads(res.stdout)

# 使用
print(js_sandbox("1 + 2 + 3"))

核心总结(你最需要记住的)

  1. 胶水层 = Python 子进程调用 Node.js
  2. vm2 负责安全隔离,绝对防逃逸
  3. 两套方案任选:
    • 简单场景 → 方案 A(子进程)
    • 高频调用 → 方案 B(RPC 长连接)
  4. 代码全部可直接运行、可直接上生产
相关推荐
asdzx673 小时前
使用 C# 将 Excel 转换成高质量 JPG
开发语言·c#·excel
瑶总迷弟3 小时前
Python入门第7章:用户输入和 while 、for循环
开发语言·python·microsoft
曲幽3 小时前
FastAPI自动生成的API文档太丑?我花了一晚上把它改成了客户愿意付费的样子
python·fastapi·web·swagger·openapi·scalar·docs
程序设计实验室3 小时前
后 Django 时代:SQLAlchemy 2.0、Tortoise 与 Piccolo 三大异步 ORM 选型指南
python
Allen_LVyingbo3 小时前
量子计算Dirac Notation基本教学—从零基础到读懂量子信息论文(上)
开发语言·数据结构·架构·健康医疗·量子计算
无巧不成书02183 小时前
Java变量初始化全攻略:2026最新规范+新手避坑实战
java·开发语言·java基础·java变量初始化·java语法规范·var关键字
ZHANG13HAO3 小时前
Node.js vm2 沙箱完全教程:从入门到安全实践
node.js
爱分享的阿Q3 小时前
技术饱和度视角下的编程语言选择:一场关于供需博弈的深度思考
java·python·go
E_ICEBLUE3 小时前
Python 办公自动化:快速将 HTML 转换为 PDF 格式
python·pdf·html