单位之前用的 Thingworx 物联网平台,里面有一个编写 Node.js 代码的编辑器,编辑之后可以直接运行显示结果。最近让我整体搬到新项目里面,说是前端没办法运行,要把 js 代码传给后端让后端运行。 里面有一些自定义的语法,我的想法是关键字匹配,如果匹配到关键字,就执行对应的操作,然后再把执行之后的结果和剩下的 js 拼接起来。 但是这样做的话就有点像一个 js 翻译器了,而且效率并不高。 我找了半天,实在没有好办法。各位大佬有没有好一点的解决方法。https://ice.frostsky.com/2023/08/14/3f6c0074202ec7d325673a21efe90f31.png
1
biubiuGolang 2023-08-14 15:56:03 +08:00
GraalVM
|
2
gitignore 2023-08-14 16:00:52 +08:00
直接执行 shell 命令不行吗
```sh node --eval="JavaScript 脚本" ``` |
3
brucedone 2023-08-14 16:00:53 +08:00
一般都是 node.js 封装成 http 服务,java 后端来调用,尽量别同进程跨解释器,会有一定的兼容问题。
|
4
mmdsun 2023-08-14 16:02:40 +08:00
Java 有 ScriptEngine 能执行一些简单的 js 代码,表达式之类的。
复杂的话,你用 Java 运行 node 命令,读取流返回结果也行吧? |
5
pkoukk 2023-08-14 16:03:08 +08:00
如果只是简单的脚本的话,1# 的就可以
如果需要解析依赖,或者 import 标准库的话,可以搞个 node 服务,把编辑后的脚步发到那个服务去执行 |
6
mightybruce 2023-08-14 16:06:05 +08:00
如果是复杂的服务,还是通过服务调用服务的方式
简单的执行逻辑可以通过一些 js runtime 以及 js ast 解析来做。 |
7
virusdefender 2023-08-14 16:06:16 +08:00
runtime.getRuntime().exec 应该是最佳选择了
|
8
drvDPqg5nO7kZWhv 2023-08-14 16:07:43 +08:00
远程调用最省心吧
|
9
mightybruce 2023-08-14 16:09:27 +08:00
有一些 Java 实现的 JavaScript 引擎,可以直接被 java 调用,比如 Rhino 和 Nashorn
|
10
Jokerboozp OP @biubiuGolang
@mmdsun @mightybruce javascript 引擎我试过,但是目前单位的 js 代码里会有一些例如“let dataInfo = Things["Localhost.PostgreSQL.Database.Thing"].Update({ updateString: sql /* STRING */ });” 这样的内容,中括号里面的内容是数据库中的,然后他有一个 Update 方法,参数是用户写的 sql ,我想要执行 js 的话还需要把这段代码执行,然后再把上面那段代码替换成 sql 的执行结果。 我觉得这样有点太不符合编码常理了 |
11
Jokerboozp OP @brucedone 意思是用 Node.js 写一个 http 服务器,然后我把 js 代码直接发给 Node 服务器,接收服务器返回的结果,然后再转发给前端这样嘛
|
12
mightybruce 2023-08-14 16:18:14 +08:00
像这样的不是简单的 js 翻译,涉及到数据库驱动了, 不是表达式,正则,规则匹配引擎。你要么用 java 重写这部分逻辑,要么改装 node.js 变成 node.js 微服务调用 java 服务的形式。
|
13
Jokerboozp OP @mightybruce 嗯嗯。就是涉及到的东西实在太多,我才有点不知所措。目前看来最优解貌似是写一个 Node 服务器,然后我用 Java 转发结果。
|
14
biubiuGolang 2023-08-14 17:18:59 +08:00
@pkoukk 复杂的也可以 import 标准和第三方都 ok
|
15
biubiuGolang 2023-08-14 17:20:25 +08:00
@Jokerboozp 了解一下 esprima 提取出来执行 sql
|
16
cl903254852 2023-08-14 17:26:04 +08:00
搞个 node 的服务,获取到编辑器的代码丢给 node 服务去执行,执行完通知 java ,java 把结果给前端。
java 就是个中间人,负责传话的 |
17
Jokerboozp OP @cl903254852 两个问题:
1 、如果 Java 只是一个传话的,那为什么还需要 Java 嘞。直接让前端把 js 代码传给 node 服务器就可以了吗不是? 2 、js 里面会有“let dataInfo = Things["Localhost.PostgreSQL.Database.Thing"].Update({ updateString: sql /* STRING */ });”这样的代码,它需要连接数据库进行查询找到对应的 Update 具体是什么,我在 node 服务器里面应该怎么办呢? |
18
Jokerboozp OP @biubiuGolang 可以,我去研究研究
|
19
sofukwird 2023-08-14 17:33:37 +08:00 via Android
quickjs ?
|
20
Jokerboozp OP @sofukwird 这个好像不可以,js 代码里会有连接数据库或者查找数据之类的操作
|
21
shyangs 2023-08-14 17:48:00 +08:00
把 Java 寫的後端扔了,改用 Node.js 寫後端。
|
22
cl903254852 2023-08-14 17:55:29 +08:00
@Jokerboozp 因为你是执行 node 代码,那肯定 node 环境是最稳妥的。 我的意思是,node 服务只针对你这个编辑器的场景即可,项目其他该用 java 用 java 。node 既然是服务端肯定能连数据库
|
23
des 2023-08-14 18:04:21 +08:00
换 Nodejs 来搞吧,感觉其实都差不多,都要写 Things 相关的驱动
不过我有点好奇,你这 12 行怎么是个同步操作? |
24
des 2023-08-14 18:09:06 +08:00
不建议提取 SQL 来执行,你这前端是个编辑器,鬼知道前端会传什么东西过来
用 javascript 引擎来做也行,前提也是你得补足“ Things["Localhost.PostgreSQL.Database.Thing"] ” 相关的东西 |
25
wganbleuthall 2023-08-14 18:10:10 +08:00
包装成一个 http 服务吧
|
26
WispZhan 2023-08-14 20:06:44 +08:00
|
27
lisongeee 2023-08-14 20:21:43 +08:00
可以使用 webcontainer 直接在浏览器运行一个小型的 linux nodejs 进程
https://webcontainers.io/guides/quickstart 它由 https://stackblitz.com/ 开发,现在很多文档/问题讨论上的在线 demo 都是基于这个 |
28
lisongeee 2023-08-14 20:25:28 +08:00
艹,你们这个还要连接数据库?那看起来是一个阉割版的远程 nodejs console ,那只能用 远程 nodejs 去执行了
|
29
zhuangzhuang1988 2023-08-14 20:31:53 +08:00
包装个 grpc?
|
30
cbdyzj 2023-08-14 20:59:35 +08:00
|
31
kid1412621 2023-08-14 21:12:44 +08:00
graal
|
32
Jokerboozp OP @zhuangzhuang1988 grpc 我还没学明白,有点难度。哈哈哈哈哈哈
|
33
Jokerboozp OP @lisongeee 就是因为要连数据库,然后还有一堆自定义的语法,所以我才头大。看了各位大佬的回复看来只有写一个 node 服务才行了
|
34
Jokerboozp OP @cl903254852 明白了明白了,多谢大佬
|
35
musi 2023-08-14 22:19:19 +08:00 via iPhone
看了一圈回复都没说到点子上,你这只需要实现 ecma262 规范的引擎也可以认为是 js 引擎基本上就可以执行代码了,你的自定义语法无非是 Thing 这个对象,那你在执行代码的时候提前去定义这个对象就好了,就你给出的代码来说,中括号是属性获取语法,其实就是在获取 Thing 对象的 Localhost.PostgreSQL.Database.Thing 属性,可以用 proxy 语法拦截 getter ,获取到这个 key ,然后是.update ,也就是 Thing 对象的 Localhost.PostgreSQL.Database.Thing 属性值是个对象,对象里面有个 update 方法,你再实现一下就行。
|
36
musi 2023-08-14 22:21:01 +08:00 via iPhone
另外就这个代码来说,只要做好鉴权前端是完全可以执行的
|
37
Jokerboozp OP @musi 但是我给出的这个是其中一个的代码,还有其他的 Thing 对象的属性,是由用户自定义来写的,每个属性有哪些方法也是用户自定义来写的。如果按照您说的这样,每一个属性我都实现方法的话,感觉不太能实现诶。刚开始写的时候我是用 jvm 的 js 引擎来写的,我觉得应对这种情况不太可行。
|
38
musi 2023-08-14 22:35:09 +08:00 via iPhone
@Jokerboozp 你还是没理解,属性不管是谁定义它只要定义了就行,平台方和用户方无所谓,你只需要封装特定的 sdk 就行
|
39
musi 2023-08-14 22:42:56 +08:00 via iPhone
@Jokerboozp 你中括号里面的内容,完全是语义化的,host.数据库类型.Datebase.表名,你用 proxy 拦截到 key 时就去找对应的数据库就行了,这也不是说一个属性定义一个方法,完全就是一个通用的方法
|
40
Jokerboozp OP @musi 不是的,他有的会写成 Things[thing]这样,这里面不一定是数据库,可能是另一个方法集合的名字,然后他又用里面的某一个方法
|
41
musi 2023-08-14 23:12:56 +08:00 via iPhone
@Jokerboozp 这就相当于一个参数了,不管你是用什么方式你都得自己去实现对应的参数应该执行的方法,不是说你用个 node.js 什么东西写个服务它就自己有这些东西,这个平台是你们自己定义的不是么
|
42
musi 2023-08-14 23:16:38 +08:00 via iPhone
我劝你也别折腾了,让你们公司前端做吧,专业的人做专业的事
|
43
biubiuGolang 2023-08-17 10:24:46 +08:00
@Jokerboozp 在 GraalVM 上使用 polyglot 执行多语言是没啥问题的,这里面包括多语言事务和 sandbox 控制,以及在 js 中调用 java java 调用 js ,你如果有了后续的更新可以回一下贴 ~
|
44
Jokerboozp OP @biubiuGolang 单位用的 jdk8 ,GraalVM 的新版本不支持,只能用老版本,但是我电脑是 M1 pro 的 MacBook ,又跑不起来老版本的 GraalVM 。所以现在在试着用 J2V8 写
|