micro-app icon indicating copy to clipboard operation
micro-app copied to clipboard

自定义fetch 拦截被基座劫持为fetch请求的script 并做代理, 代理能请求到资源, 但是script未能正常加载

Open huchaolin opened this issue 3 years ago • 1 comments

问题描述

微应用第三方地图资源加载(百度地图),通过自定义fetch的方式拦截原本为script的方式请求但被基座劫持为fetch的方式请求的第三方静态资源并做代理转发 并且能够拿到返回的资源, 但是静态资源并没有按照原有script的方式正常加载, 页面一片空白, 微应用伪代码:

  <script type="text/javascript" src="//api.map.baidu.com/api?type=webgl&v=1.0&ak=你的秘钥">
  </script>

基座伪代码 :

const baiduProxyDomain = [
    'api.map.baidu.com',
    'dlswbr.baidu.com',
    'hm.baidu.com',
];
 microAppService.start({
   fetch(url, options, appName) {
                const AudienceExplorerAppId = 'AudienceExplorer';
                if (appName == AudienceExplorerAppId) {

                    const domain = baiduProxyDomain.find(v => url.includes(v));
                    if (domain) {
                        let pureUrl = url.replace(domain, '').replace('http:', '').replace('https:', '');
                        pureUrl = removeTailingSlash(pureUrl);
                        pureUrl = removeFrontSlash(pureUrl);

                        const proxyUrl = `/!/${domain.replace(/\./g, '-')}/api/${pureUrl}`;

                        return window.fetch(proxyUrl, options).then((res) => {
                            return res.text();
                        });
                    }
                }
 
                return window.fetch(url, options).then((res) => {
                    return res.text();
                })
            }
})

期间已经做了很多尝试了, 包括: 1.把子应用加载资源放到基座,再在子应用通过window.rawWindow的方式去拿实例(对于上述type=webgl的情况的百度地图会报部分cant read property of null的错误) 2.重写document.write 与document.createElement 想实给动态创建的资源script标签添加上ignore属性, 但是没有任何效果,以下为在微应用html中重写的代码:

  <script type="text/javascript">
  
    const origWriteFunc = document.write;
    document.write = function (str) {
      str = str.replace('<script', '<script ignore ');
      return origWriteFunc.apply(this, [str]);
    }

    const origCreateElementFunc = document.createElement;

    document.createElement = function () {
      let tag = arguments[0];

      if (tag === 'script' || tag === 'link') {
        let elementResult = origCreateElementFunc.apply(document, arguments);

        elementResult.setAttribute('ignore', 'true');

        return elementResult;
      }
      return origCreateElementFunc.apply(this, arguments);
    }
  </script>

现在已经黔驴技穷了, 真的不知道该怎么解决这个问题了, 真心希望你们能给出一个可行的解决方案。。

复现步骤

  1. 按照这个地址示例在微应用中创建组件并在基座访问该微应用就能复现这个问题,https://lbs.baidu.com/index.php?title=jspopularGL/guide/show

上传截图

这是应用本身通过script请求的资源

image

这是上面的最开始的两个script被基座劫持为fetch请求后, 我通过配置代理请求到的资源, 能看到资源是能够请求到的

image image image

补充说明

当我将第三方资源下载下来放在微应用中(这里指的是c资源: a资源请求到b资源,b资源又通过document.write('<script src='xxx' ></script>')的方式加载c资源, c资源中也有动态创建script加载资源的逻辑)以本地资源的方式引入时, 基座fetch能拦截到这个c资源里面动态创建script加载的其它资源并代理转发(这里自己配置了nginx)成功拿到返回的内容;但是同样会报一个错误, 该错误也出现在将第三方资源(a资源)直接以script的方式写在基座的html上并在微应用中以window.rawWinfow访问该资源加载在window上的实例时, 报错如下 image

另外我将上面报报错的地方强制加上判断语句避免报错之后, 地图能正常渲染了, 但是点击地图左上方勾选区域的按钮, 又会报getAttribute is not a function的错误, 点击看好像是microApp相关的逻辑 image image image

后续, 提问者自己的解决方案, 希望能帮到遇到同样问题的人

试了很多方法都不行, 怀疑是百度地图底层实现机制不兼容现有MicroApp的方案, 所以换了 高德地图, 同样也是在微应用端引入,在基座访问, 同样的功能, 没有跨域问题,没有报错问题, 没有任何问题

环境信息

micro-app版本:"@micro-zoe/micro-app": "0.8.8" 主应用前端框架&版本:"react": "^16.12.0", "react-dom": "^16.12.0", "react-router-dom": "^5.3.3" 子应用前端框架&版本:"react": "^17.0.1", "react-dom": "^17.0.1", "react-router-dom": "^5.2.3", 构建工具&版本:"webpack": "^5.64.0"

huchaolin avatar Aug 11 '22 11:08 huchaolin

我们最近也发现百度地图接入困难,目前在尝试开发一个插件来解决

bailicangdu avatar Aug 12 '22 08:08 bailicangdu

我们最近也发现百度地图接入困难,目前在尝试开发一个插件来解决

这个有进展吗? 有百度地图的太难受了。。。 进行不下去

skyLoveSnap avatar Nov 22 '22 05:11 skyLoveSnap

我们最近也发现百度地图接入困难,目前在尝试开发一个插件来解决

想问下现在有好的解决办法吗?

X-J-C avatar Nov 25 '22 03:11 X-J-C

1、百度地图放在基座应用 (直接将有百度地图的应用作为了基座应用) 或者 2、 将百度地图js下载本地引用(还没这样用,不知道可不可以)

skyLoveSnap avatar Nov 25 '22 03:11 skyLoveSnap

1、百度地图放在基座应用 (直接将有百度地图的应用作为了基座应用) 或者 2、 将百度地图js下载本地引用(还没这样用,不知道可不可以)

在基座引用不会报这个错吗? image

X-J-C avatar Nov 25 '22 03:11 X-J-C

1、百度地图放在基座应用 (直接将有百度地图的应用作为了基座应用) 或者 2、 将百度地图js下载本地引用(还没这样用,不知道可不可以)

在基座引用不会报这个错吗? image

有报错需要处理一下,我看上边很多提到本地化,所以我把百度的js、css引入本地; 步骤: 1、子应用中引入js(initBaidu.js)、css(需要添加ignore); 2、主应用中用插件处理: image 主要处理百度js里边动态加载的script,给他们都加上忽略属性,让框架忽略他。 这样实现了正常加载

ScorpionFishBrisket avatar Jun 08 '23 08:06 ScorpionFishBrisket

刚刚增加了一个npm包,可以用这个包 @fishbelly/plugin-baidu-micro

ScorpionFishBrisket avatar Jun 08 '23 13:06 ScorpionFishBrisket

按此操作 do like this: https://github.com/micro-zoe/micro-app/issues/1009

iYogic2 avatar Dec 13 '23 09:12 iYogic2