使用iframe将帆软报表集成在Vue大屏中

使用iframe将帆软报表集成在Vue大屏中,过程中遇到好几个坑,特此记录。

1.思路

  1. 请求帆软获取token的接口拿到token,存到cookie中

  2. 携带cookie请求帆软的报表页面。将其以iframe的形式嵌入vue报表中

2.实现

2.1 请求获取token接口

·跨域问题

这里遇到了第一个问题,请求接口的时候 http get请求报错403,浏览器报错

Access to XMLHttpRequest at
'http://帆软服务器ip/getToken' from origin 'http://代理服务器ip' 
has been blocked by CORS policy: 
No 'Access-Control-Allow-Origin' header is present on the requested resource.

是浏览器的同源策略引起的跨域问题。
经过查阅资料,生产环境解决跨域问题的办法有很多JSONP,CORS,反向代理等。
这里我采用的是反向代理。
只需要在代理服务器那里做个反向代理即可。项目部署架构如下:
图片1
一开始我以为使用的Nginx做的代理,同事反馈说是使用的Apache做的代理,两段设置都贴上吧:

Nginx:(没测试过)
location ^~ /getToken{
  proxy_pass http://帆软服务器ip/getToken;
}

Apache:
ProxyRequests Off
  ProxyPass /getToken  http://帆软服务器ip/getToken
  ProxyPassReverse /getToken  http://帆软服务器ip/getToken

注意: 这里我犯了个低级错误。设置了代理以后,那么发Axios请求的时候,就应该是请求服务器的ip,而不是直接请求帆软的ip,即:

utils.ajax.get("http://帆软服务器ip/getToken", {}) // 错误
utils.ajax.get("http://代理服务器ip/getToken", {}) // 正确

2.2 将token存到cookie中

这里无需多说

setCookie(cname, cvalue, exhours) {
  let d = new Date();
  d.setTime(d.getTime() + (exhours * 60 * 60 * 1000));
  let expires = "expires=" + d.toUTCString();
  document.cookie = cname + "=" + cvalue + "; " + expires;
},
getCookie(cname) {
  let name = cname + "=";
  let ca = document.cookie.split(';');
  for (let i = 0; i < ca.length; i++) {
    let c = ca[i].trim();
    if (c.indexOf(name) === 0)
      return c.substring(name.length, c.length);
  }
  return null;
},
removeCookie(cname) {
  this.setCookie(cname, '', -1);
}

2.3 携带token请求帆软报表页面

· cookie跨域问题

首先仍然是跨域问题,当iframe中的地址跟地址栏中的地址存在跨域时,请求将不能携带cookie。具体表现为:即使我拿到了token存在cookie中,请求报表页面时还会被拦截到登陆注册页,而且输入账号密码也无法登陆,无限循环登陆注册页。
解决仍然采用Apache的反向代理:

ProxyPass /fineBI/decision http://帆软服务器ip:port/fineBI/decision

· iframe 额外携带头文件

解决了跨域问题之后,虽然iframe的src携带了cookie,但仍然无法登陆,经过跟帆软的沟通,他们还需要额外在请求头提供Authorization: Bearer token来进行身份校验(我nm…)
iframe src是无法携带请求头的,只能另辟蹊径了。

这里参考了这位大大的文章: VUE+iframe添加请求头

<iframe id="iframe" src="" />

setTimeout(() => {
  var iframe = document.querySelector("#iframe");
  this.populateIframe(iframe, [["Authorization", "Bearer " + getToken()]]);
}, 0);

methods: {
   populateIframe(iframe, headers) {
     var xhr = new XMLHttpRequest();
     xhr.open("GET", 'http:localhost:8080/xxx');
     xhr.responseType = "blob";
     headers.forEach((header) => {
       xhr.setRequestHeader(header[0], header[1]);
     });
     xhr.onreadystatechange = () => {
       if (xhr.readyState === xhr.DONE) {
         if (xhr.status === 200) {
           iframe.src = URL.createObjectURL(xhr.response);
         }
       }
     };
     xhr.send();
   },
 }

· XMLHttpRequest中responseType 采用blob的坑

这样改写完成以后,确实可以请求网址得到帆软的页面元素,但是仍然有两个问题:

  1. 帆软iframe中script中的jquery语法会报错。(注:如果不镶嵌,直接用浏览器打开则不会有这个问题)
    tupian 2
  2. 获得的页面元素元素中,body是空的。
    在这里插入图片描述虽然没弄明白为什么为这样,有知道的朋友可以留言告诉我。但是页面显示不出来是肯定不行的。期间也尝试过给整个vue项目装jquery,但是引入的第三方页面并不能共享项目中的jquery。

经过帆软前辈的提醒,考虑到是不是xhr.responseType = "blob"这一行的问题,遂进行修改,使用 xhr.responseType = "text"

修改后的方法:

populateIframe(iframe, headers) {
     var xhr = new XMLHttpRequest();
     xhr.open("GET", 'http:localhost:8080/xxx');
     xhr.responseType = "text";
     headers.forEach((header) => {
       xhr.setRequestHeader(header[0], header[1]);
     });
     xhr.onreadystatechange = () => {
       if (xhr.readyState === xhr.DONE) {
         if (xhr.status === 200) {
           // iframe.src = URL.createObjectURL(xhr.response);
           let iframe = document.getElementById('frame-box');
            iframe = iframe.contentWindow || ( iframe.contentDocument.document || iframe.contentDocument);
            iframe.document.open();
            iframe.document.write(xhr.response);
            iframe.document.close();
         }
       }
     };
     xhr.send();
   },

修改之后成功把页面展示了出来。

· 页面能显示不能导出。cookie path的问题

就在我十分欣喜准备写篇博客庆祝一下的时候,噩耗又来了。页面是可以展示了,但是不能使用报表页面上的导出和打印功能,我他喵的。得,继续看吧。
在这里插入图片描述

根据我英语六级的水平判断,报表在打印之前,会发一个请求来检查是否登陆。
图片5
肯定是这个请求导致它判断我没有登陆。我又让同事分别在我们嵌入的报表页面和在浏览器上的报表页面点击导出来判断头文件还存在哪些不同,经过对比,我发现
我从帆软接口请求到的token, 只附带到了header Authorization中,并没有附带到cookie中,而我本地测试的时候确实是附带到了cookie中。这令我百思不得其解。
经过详细的对比,把问题锁定在cookie的path上:
本地:
在这里插入图片描述
服务器:
在这里插入图片描述
经过打包,服务器上的path,变为了/myprojectname。cookie中的path是cookie生效的范围。path不同,自然没法附带这个cookie。
所以我们修改上面提到的getCookie函数:

document.cookie = cname + "=" + cvalue + "; " + expires + '; path=/;'

至此,打印、导出也可以正常使用。
梳理一下认证过程,之前页面单点登录的时候,cookie未附带也登录成功,说明登录的时候只验证了Authorization,而打印、导出的时候又只验证cookie,不得不感叹帆软的验证方式有点儿奇怪。


左手是过目不忘的萤火,右手是十年一个漫长的打坐。

  • 5
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
使用iframe实现项目集成是一种常见的方法,它可以将一个页面嵌入到另一个页面,实现不同项目之间的集成。引用\[1\]提到,iframe具有极强的隔离性,可以将页面内的操作限制在自身范围内,同时具有松散的耦合和高鲁棒性。这使得iframe成为一些在线编辑平台的常用技术。 然而,使用iframe也存在一些负面效果。引用\[2\]指出,iframe会带来性能开销,每个iframe都会创建一个新的浏览器上下文,导致额外的内存和CPU消耗。此外,iframe破坏了页面的语义化,对无障碍可访问性标准造成影响,并且对SEO不友好,因为爬虫会将使用iframe的页面当作两个不同的页面进行索引。 因此,在使用iframe实现项目集成时,需要权衡其优势和劣势。如果对于隔离性和易于实现有较高的要求,并且不关注性能开销和SEO问题,那么使用iframe可能是一个合适的选择。但如果对性能和可访问性有更高的要求,可能需要考虑其他的集成方案。 #### 引用[.reference_title] - *1* *2* [让iframe为项目增加更多可能性](https://blog.csdn.net/qq_43624878/article/details/126562131)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [使用iframe帆软报表集成Vue大屏](https://blog.csdn.net/shijizhe1/article/details/126538042)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小雅痞

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值