You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何修改Ajax的src属性且不发起新请求?解决iframe认证请求异常

问题分析与解决方案

咱们先拆解下你遇到的两个核心问题:

为什么会出现无认证头的GET请求(返回401)?

当你执行$('#dashboard').attr('src', 'https://mysystem.xxxx');这行代码时,浏览器会单独发起一个全新的GET请求去加载这个iframe的源地址——这个请求和你之前的AJAX请求完全是独立的,根本不会继承AJAX里设置的Authorization头或者withCredentials配置。这是浏览器的同源策略和iframe加载机制决定的,所以这个无认证的请求自然会被目标系统拒绝,返回401。

为什么移除src行后静态资源会404?

你通过AJAX拿到HTML内容后,直接塞进了iframe的<html>标签里,但此时iframe的src是空的,浏览器会把当前页面的域名作为基准,去请求那些相对路径的静态资源(比如/css/style.css会被解析成当前页面域名下的路径),而不是目标系统的域名,所以肯定找不到对应的资源,返回404。


针对这个问题的几种解决思路

思路1:利用Cookie共享认证(优先推荐)

既然你的AJAX请求已经设置了withCredentials: true,如果目标系统的CORS配置正确(返回Access-Control-Allow-Credentials: true,且允许当前域名跨域),那么AJAX请求成功后,目标系统返回的认证Cookie会被浏览器保存。这时候你可以直接设置iframe的src为目标地址,浏览器会自动携带这个Cookie,不需要手动加Authorization头:

$.ajax({
  url: 'https://mysystem.xxxx/',
  beforeSend: function(xhr) {
    xhr.withCredentials = true;
    xhr.setRequestHeader("Authorization", "Basic Z2Vxxxxxxxxxxx==");
  },
  success: function() {
    // 此时Cookie已保存,直接加载iframe即可
    $('#dashboard').attr('src', 'https://mysystem.xxxx');
  }
});

注意:目标系统需要支持基于Cookie的认证,并且Cookie的域、路径等配置要允许当前页面的域名访问。

思路2:修正静态资源的绝对路径

如果你必须用AJAX获取HTML再塞进iframe,那需要把返回的HTML里所有相对路径的静态资源,都替换成目标系统的绝对路径。比如:

  • <link href="/css/main.css">改成<link href="https://mysystem.xxxx/css/main.css">
  • <script src="/js/app.js">改成<script src="https://mysystem.xxxx/js/app.js">
  • 图片的src同理处理

你可以在AJAX的success回调里用正则表达式批量替换这些路径:

success: function(data) {
  // 替换所有相对路径为绝对路径
  const processedData = data.replace(/(src|href)="\/(.*?)"/g, '$1="https://mysystem.xxxx/$2"');
  $('#dashboard').contents().find('html').html(processedData);
}

这种方式的缺点是如果目标页面有动态生成的资源路径,或者特殊的路径规则,可能会漏替换或者替换错误。

思路3:使用代理服务器中转请求

如果目标系统的CORS或认证规则没办法调整,你可以在自己的服务器上搭建一个代理接口:

  1. 前端请求自己的代理接口,带上认证信息
  2. 代理接口向后端系统发起请求,添加Authorization
  3. 代理把后端返回的内容(包括HTML和静态资源)转发给前端
  4. 前端的iframe直接加载代理接口的地址

这样浏览器只会和你的代理服务器交互,不会有跨域问题,认证信息也由代理统一处理,避免了iframe请求无认证的问题。


内容的提问来源于stack exchange,提问作者gbernardes

火山引擎 最新活动