Javascript 无法将脚本加载到iframe中

Javascript 无法将脚本加载到iframe中,javascript,html,iframe,Javascript,Html,Iframe,测试页面: 在这个测试页面上,你可以看到3个相互嵌入的。每个在其标记中包含一个标记 问题是:浏览器将仅加载第一个中的。另外两个标记将出现在dom中,但浏览器甚至不会尝试加载它们。这个问题不是特定于浏览器的,它可以在chrome、firefox、ie中重新生成。这个问题不能通过添加超时或在附加脚本之前等待来解决。所有iFrame都以编程方式生成内容似乎很重要;如果用带有实际src链接的iframe替换此iframe,则问题将消失 问题是:如何将脚本加载到iFrame 2和iFrame 3中 完整测

测试页面:

在这个测试页面上,你可以看到3个相互嵌入的
。每个
在其
标记中包含一个
标记

问题是:浏览器将仅加载第一个
中的
。另外两个
标记将出现在dom中,但浏览器甚至不会尝试加载它们。这个问题不是特定于浏览器的,它可以在chrome、firefox、ie中重新生成。这个问题不能通过添加超时或在附加脚本之前等待来解决。所有iFrame都以编程方式生成内容似乎很重要;如果用带有实际src链接的iframe替换此iframe,则问题将消失

问题是:如何将脚本加载到iFrame 2和iFrame 3中

完整测试代码:

// It doesn't matter if the scripts exist or not
// Browser won't try to load them either way
var scripts = [
    '//testdomain.test/script1.js',
    '//testdomain.test/script2.js',
    '//testdomain.test/script3.js'
];

function createIFrame(win, onCreated) {
    var iframe = win.document.createElement('iframe');
    iframe.onload = function () {
        onCreated(iframe);
    };
    win.document.body.appendChild(iframe);
}

function loadScript(win, url) {
    var script = win.document.createElement('script');
    script.src = url;
    script.onload = function() {
        console.log("Script " + url + " is loaded.");
    };
    win.document.getElementsByTagName('head')[0].appendChild(script);
}

createIFrame(window, function(iframe1) {
    loadScript(iframe1.contentWindow, scripts[0]);
    createIFrame(iframe1.contentWindow, function (iframe2) {
        loadScript(iframe2.contentWindow, scripts[1]);
        createIFrame(iframe2.contentWindow, function (iframe3) {
            loadScript(iframe3.contentWindow, scripts[2]);
        });
    });
});

您的代码运行正常-->

确保在或上执行createIFrame


在这个问题中,你可以看到我在宣布协议:

/* This is valid to omit the http:/https: protocol.
   In that case, browser should automatically append 
   protocol used by the parent page */
var scripts = [
    '//testdomain.test/script1.js',
    '//testdomain.test/script2.js',
    '//testdomain.test/script3.js'
];
问题是,通过编程创建的iFrame具有协议
about:
(或
javascript:
,具体取决于创建它们的方式)。我仍然无法解释为什么第一个脚本正在加载,或者为什么其他两个脚本根本没有显示在“网络”选项卡中,但我想这并不重要

解决方案:要么显式使用
https://
,要么使用类似以下代码的程序附加协议:

function appendSchema(win, url) {
    if (url.startsWith('//')) {
        var protocol = 'https:';
        try {
            var wPrev = undefined;
            var wCur = win;
            while (wPrev != wCur) {
                console.log(wCur.location.protocol);
                if (wCur.location.protocol.startsWith("http")) {
                    protocol = wCur.location.protocol;
                    break;
                }
                wPrev = wCur;
                wCur = wCur.parent;
            }
        } catch (e) {
            /* We cannot get protocol of a cross-site iframe.
             * So in case we are inside cross-site iframe, and
             * there are no http/https iframes before it,
             * we will just use https: */
        }
        return protocol + url;
    }
    return url;
}

我成功地使用了一种比OP在报告中提出的更简单的方法。我使用以下方法生成URL:

new URL(scriptURL, window.location.href).toString();
其中,
scriptURL
是需要固定以获得适当协议的URL,
window
是保存脚本的
iframe
元素的父元素。这可以处理与OPs示例URL不同的场景:如相对URL(
./foo.js
)或不以主机开头的绝对URL(
/foo.js
)。以上代码在我的情况下就足够了

如果我要通过OP使用的窗口层次结构复制搜索,我可能会执行以下操作。这是打字脚本代码。去掉类型注释以获得普通JavaScript

function url(win: Window, path: string): string {
  // We search up the window hierarchy for the first window which uses
  // a protocol that starts with "http".
  while (true) {
    if (win.location.protocol.startsWith("http")) {
      // Interpret the path relative to that window's href. So the path
      // will acquire the protocol used by the window. And the less we
      // specify in `path`, the more it gets from the window. For
      // instance, if path is "/foo.js", then the host name will also be
      // acquired from the window's location.
      return new URL(path, win.location.href).toString();
    }

    // We searched all the way to the top and found nothing useful.
    if (win === win.parent) {
      break;
    }

    win = win.parent;
  }

  // I've got a big problem on my hands if there's nothing that works.
  throw new Error("cannot normalize the URL");
}

如果窗口链没有产生任何有用的结果,我没有默认的返回值,因为这将表明一个比生成URL更大的问题。我的设置中的其他地方可能有问题。

您的控制台中有哪些错误?谢谢。尽管你的回答没有解决我的问题,但它提供了解决问题的重要线索(见我的答案)。
function url(win: Window, path: string): string {
  // We search up the window hierarchy for the first window which uses
  // a protocol that starts with "http".
  while (true) {
    if (win.location.protocol.startsWith("http")) {
      // Interpret the path relative to that window's href. So the path
      // will acquire the protocol used by the window. And the less we
      // specify in `path`, the more it gets from the window. For
      // instance, if path is "/foo.js", then the host name will also be
      // acquired from the window's location.
      return new URL(path, win.location.href).toString();
    }

    // We searched all the way to the top and found nothing useful.
    if (win === win.parent) {
      break;
    }

    win = win.parent;
  }

  // I've got a big problem on my hands if there's nothing that works.
  throw new Error("cannot normalize the URL");
}