扣代码技巧:如何调用扣好的代码(不是 pyexecjs)

大家好,今天分享一种远程调用 JS 代码的技巧,学会了它就可以弃用 pyexecjs 了。

pyexecjs现状

pyexecjs 在 2018 年已经停止更新了,虽然现在还可以使用,不过只有一些简单的脚本还可以用用,遇到复杂的脚本可能会有不兼容的情况。

image-20250412125952927

image-20250412130026304

image-20250412130043242

image-20250412130108653

而且 pyexecjs 底层其实就是封装了 Popen 类,在不同的 JS 环境中使用不同的命令运行对应的 JS 脚本,每次需要执行 JS 时,都要新建一个进程。而进程的创建在操作系统看来是一个比较重的操作,从效率上来说还是比较低的。接下来分享一种更加高效并且易于使用的方法来远程调用 JS。

远程调用 JS

这个方法就是使用 nodejsexpress 框架来实现一个简单的 http 服务器,利用 require 关键字导入扣好的代码,然后启动服务器即可。

来看一个示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
const express = require('express');
const app = express();
const bodyParser = require('body-parser');
const match6 = require('../match/match6/code');
// 调整参数大小限制,否则会提示参数过大。
app.use(bodyParser.json({limit: '50mb'}));
app.use(bodyParser.urlencoded({limit: '50mb', extended: true}));
app.use(bodyParser.json());

app.post('/match6', (req, res) => {
let result = req.body;
if (!result.p) {
return res.status(400).json({error: '参数缺失'});
}
let data = match6(result.t.toString(), result.p);
const responseData = {data: data};
res.set('Content-Type', 'application/json')
res.json(responseData);
});

app.listen(8919, () => {
console.log("开启服务,端口8919", new Date().toString())
})

通过 require 关键字导入所需要的代码,并且在路由中调用。当然了,这个脚本作为 demo 使用没有问题,但是要在生产环境中使用需要考虑更多的情况,例如鉴权,动态更新,速率限制,并发操作等等。

沙盒

当然了,上面的示例使用的是 nodejs 本体执行扣好的 JS 代码,如果遇到那种会检测 nodejs 的,需要使用沙盒来运行 JS,否则它会导致 web 服务器启动失败的,之前我就遇到过一次。

在沙盒中运行 JS 的方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
const express = require('express');
const app = express();
const bodyParser = require('body-parser');
const vm = require('vm'); // 引入 vm 模块创建沙盒

const match14 = require('../match/match14/code');
// 调整参数大小限制,否则会提示参数过大。
app.use(bodyParser.json({limit: '50mb'}));
app.use(bodyParser.urlencoded({limit: '50mb', extended: true}));
app.use(bodyParser.json());

app.post('/match14_eval', (req, res) => {
let result = req.body;
if (!result.js) {
return res.status(400).json({error: '参数缺失'});
}
// 创建沙盒环xxxxxx
const sandbox = {
window: {'href': 'https://match.xxxxx.cn/match/14'},
atob: (str) => Buffer.from(str, 'base64').toString('binary'), // 实现 atob
btoa: (str) => Buffer.from(str, 'binary').toString('base64') // 实现 btoa
};
try {
// 在沙盒中执行代码
vm.createContext(sandbox);
vm.runInContext(result.js, sandbox);
} catch (e) {
return res.status(500).json({error: '代码执行失败', details: e.message});
}
let t8 = Date["parse"](new Date()) * 8;
let t = Date["parse"](new Date());
let data = match14(t8, t, sandbox.window['v14'], sandbox.window['v142'], result.page)
// const responseData = {data: {'t8': t8, 't': t, 'v14': sandbox.window['v14'], 'v142': sandbox.window['v142']}};
const responseData = {data: data};
res.set('Content-Type', 'application/json')
res.json(responseData);
});


app.listen(8919, () => {
console.log("开启服务,端口8919", new Date().toString())
})

在沙盒中运行的 JS 脚本,不会污染现有的 nodejs 环境,也能避免执行到一些危险的脚本危害自己的系统。

总结

以上就是远程调用 JS 脚本的方法了,后续在执行 JS 代码时,只需要发送 http 请求并且填入参数,即可获得 JS 脚本的运行结果,感兴趣的小伙伴可以试一下。该方法的稳定性和效率都比较高,如果遇到那种耗时很久才能返回的 JS,也可以增加多个服务和负载均衡,做成一个小小的微服务。

本文章首发于个人博客 LLLibra146’s blog

本文作者:LLLibra146

更多文章请关注公众号 (LLLibra146):LLLibra146

版权声明:本博客所有文章除特别声明外,均采用 © BY-NC-ND 许可协议。非商用转载请注明出处!严禁商业转载!

本文链接
https://blog.d77.xyz/archives/undefined.html