V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐关注
Meteor
JSLint - a JavaScript code quality tool
jsFiddle
D3.js
WebStorm
推荐书目
JavaScript 权威指南第 5 版
Closure: The Definitive Guide
yazoox
V2EX  ›  JavaScript

大家有没有在自己的代码里面,动态的下载并执行一段第三方的 js 文件或者代码?

  •  
  •   yazoox · 2022-03-31 11:34:56 +08:00 · 3558 次点击
    这是一个创建于 1002 天前的主题,其中的信息可能已经有所发展或是发生改变。

    现在客户有一个需求,要在我们的一个包 /package ( React, typescript,编写的,用于显示数据的),展示数据的之前,要从客户的一个服务器上,下载一个.js 文件,执行一下,生成一些数据,导入到我们的数据中,然后再渲染展示数据。

    这个 js 文件,是动态决定的。甚至可能不止一个。

    这个有没有比较好的实践方法?

    24 条回复    2022-04-02 16:05:21 +08:00
    puzzle9
        1
    puzzle9  
       2022-03-31 11:39:41 +08:00
    无头浏览器?
    terranboy
        2
    terranboy  
       2022-03-31 11:45:01 +08:00
    定时任务?
    nicevar
        3
    nicevar  
       2022-03-31 11:53:49 +08:00
    在客户端执行?看 js 多复杂了,简单的 js 解释器就行,如果复杂的话创建一个不可见的 webview 来处理,服务端可以用 headless chrome 。
    shintendo
        4
    shintendo  
       2022-03-31 11:58:04 +08:00
    创建 script 标签不就行了
    DrakeXiang
        5
    DrakeXiang  
       2022-03-31 11:59:03 +08:00
    为啥不能在服务端干这个,客户端的话只能 eval 了吧,看起来挺不安全的样子
    crysislinux
        6
    crysislinux  
       2022-03-31 12:01:33 +08:00
    动态 import 就可以了,如果文件名会变化或者可能会加载多个文件,可以先 import 一个动态的列表,然后再根据列表 import 其他的。以前我用 systemjs 做过,现在可以用 dynamic import
    ysc3839
        7
    ysc3839  
       2022-03-31 12:04:52 +08:00
    先说清楚运行环境?是浏览器吗?
    3dwelcome
        8
    3dwelcome  
       2022-03-31 12:05:51 +08:00
    @DrakeXiang 为什么都说客户端用 eval 不安全呢,我觉得挺安全啊。

    又不是服务器远程调用 RPC 不安全,本地就算 JS 被注入修改,也不会影响到其他用户。
    3dwelcome
        9
    3dwelcome  
       2022-03-31 12:08:43 +08:00
    而且浏览器环境下,chrome 插件拥有至高无上的权利,JS 代码随时随地会被入侵。

    本来就没指望 JS 运行绝对的安全,用个 eval 或者创建 script 标签,都是常规操作了。
    seakingii
        10
    seakingii  
       2022-03-31 12:36:44 +08:00
    浏览器的话,可以动态插入 script 到 dom 里.

    var script = document.createElement('script'),
    script.type = 'text/javascript';


    ....

    后面自己搞定
    Puteulanus
        11
    Puteulanus  
       2022-03-31 13:15:49 +08:00   ❤️ 1
    这不就是 JSONP 吗
    icyalala
        12
    icyalala  
       2022-03-31 13:24:48 +08:00   ❤️ 4
    @3dwelcome 它要是拿了用户 token 传走,或者挂马攻击别人,再或者挂个挖矿的导致运营商封禁,这都有可能啊。
    对面这种显然没有安全意识,如果你选择相信对面,结果对面被攻击了导致你程序影响用户,那最终你还得背锅。

    另外浏览器插件里面乱搞这个屡见不鲜了: https://www.v2ex.com/t/390135 ,但使用插件的时候你的角色是用户,不是开发者了,你可以做出合理选择来保护自己。
    DOLLOR
        13
    DOLLOR  
       2022-03-31 13:53:15 +08:00
    第三方应该只提供接口返回数据,而不是返回 js 代码。
    dany813
        14
    dany813  
       2022-03-31 14:19:45 +08:00
    6 楼说的不错,如果就一个 js 直接动态加载就行,你现在是没发确定有多少个 js ,需要一个 js 映射文件
    libook
        15
    libook  
       2022-03-31 14:37:38 +08:00
    JS 动态在 DOM 树里插 script 标签就行。
    或者浏览器比较新就动态 import 。

    当然安全问题还是得考虑的,否则会有扯皮风险,可以考虑让客户的服务端提供处理数据的接口,或者前端加个沙盒机制从沙盒里跑客户的 js 文件。
    ychost
        16
    ychost  
       2022-03-31 14:50:46 +08:00
    为啥一定要 js ,他们给接口返回 JSON 不行吗,js 太 hack 了
    yazoox
        17
    yazoox  
    OP
       2022-03-31 17:12:38 +08:00
    @seakingii 如果这段 js 运行完,有返回值,比如回返一个 json 文件,怎么获取到呢?
    yazoox
        18
    yazoox  
    OP
       2022-03-31 17:18:23 +08:00
    @libook
    "或者前端加个沙盒机制从沙盒里跑客户的 js 文件。"兄弟,这段话是什么意思?怎么在前端添加沙盒?
    开一个 worker.js ?跑在这个里面,然后通过 postmessage 通讯?,etc.
    seakingii
        19
    seakingii  
       2022-03-31 17:27:23 +08:00
    @yazoox 动态导入的 JS 你们约定好,里面有约定好的方法

    比如你动态导入一个名字为 get_user_info_1.js ,里面必定有个同名的方法 get_user_info1_(你传入的数据)
    seakingii
        20
    seakingii  
       2022-03-31 17:28:45 +08:00
    @yazoox

    下面是例子代码,不一定能直接跑,没测试过

    ```
    function importJsFile(jsUrl){

    let jsId = hash(jsUrl);//根据 jsUrl 生成一个唯一的 hash 值,避免重复 import

    if(document.getElementById(jsId)) return;


    let newElement=document.createElement("script");
    newElement.type="text/javascript";
    newElement.id = jsId;
    newElement.src=jsUrl;

    var head=document.getElementsByTagName("head")[0];
    head.appendChild(newElement);

    }


    function importJsAndInvoke(userId){
    let functionName = 'get_user_info_1';
    let jsUrl = 'http://baidu.com/js/get_user_info_1.js';

    //导入外部 JS
    importJsFile(jsUrl);

    //调用外部 JS 里的一个方法
    let result = window[functionName](userId);
    console.dir(result);

    }
    ```
    libook
        21
    libook  
       2022-03-31 18:39:39 +08:00
    @yazoox #16 我没有具体做过,我的思路就是用 WebWorkers 、WebAssembly 等天然提供沙盒的机制来跑,注意它们的沙盒基本是运行方面的隔离,一些同域的资源也可能可以访问,具体可以去 MDN 上仔细研究一下。
    还可以找找看有没有一些前端沙盒的库,我听说 Deno 可以在浏览器端作为一个沙盒环境运行(本质好像也是 WebAssembly ),本人没用过,你可以去看一下是不是满足需要。

    沙盒和外界程序之间使交流用 postmessage 等机制,对数据交流进行严格管制,就可以避免安全问题,同时记得记录关键日志(可以从前端发到你们自己的日志服务器),以便于审计和回溯。
    yazoox
        22
    yazoox  
    OP
       2022-04-01 09:01:00 +08:00
    @seakingii
    let result = window[functionName](userId);
    加载的 script 中的函数是通过 window[name]访问的啊。got it. thx

    @libook 嗯,用 WebWorkers 试试~ thx
    han3sui
        23
    han3sui  
       2022-04-01 17:25:33 +08:00
    npm i loadjs
    SmiteChow
        24
    SmiteChow  
       2022-04-02 16:05:21 +08:00
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5477 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 27ms · UTC 08:57 · PVG 16:57 · LAX 00:57 · JFK 03:57
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.