2017-02-10 4 views
1

Тестовая страницаhttps://jsfiddle.net/y25rk55w/Невозможно загрузить скрипт в IFRAME

На этой тестовой странице вы можете увидеть 3 «S погруженных друг в друга. Каждый содержит тег <script> в своем теге <head>.

Проблема в следующем: только <script> в начале будет загружен через браузер. Остальные два тега <script> будут присутствовать в dom, но браузер даже не попытается их загрузить. Проблема не зависит от браузера, она может быть переделана в chrome, firefox, т.е. Проблема не может быть устранена путем добавления тайм-аутов или ожидания перед добавлением скриптов. Кажется важным, чтобы все фреймы имели программно сгенерированный контент; если вы замените эти iframes фреймами с фактическими ссылками src, проблема исчезнет.

Вопрос: Как я могу загрузить сценарий в iframes 2 и 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]); 
     }); 
    }); 
}); 
+0

Какие ошибки вы получаете в своей консоли? – putvande

ответ

1

В вопросе вы можете увидеть, что я был ommiting протокол:

/* 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' 
]; 

Дело в том, программно созданные фреймы имеют протокол 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; 
} 
1

Ваш код работает отлично ->http://plnkr.co/edit/vQGsyD7JxZiDlg6EZvK4?p=preview

Убедитесь, что вы выполнить createIFrame на window.onload или DOMContentLoaded.

var scripts = [ 
    'https://cdnjs.cloudflare.com/ajax/libs/jquery/1.11.1/jquery.js', 
    'https://cdnjs.cloudflare.com/ajax/libs/jquery/1.11.2/jquery.js', 
    'https://cdnjs.cloudflare.com/ajax/libs/jquery/1.11.3/jquery.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); 
} 
window.onload = function(){ 
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]); 
     }); 
    }); 
}); 
}; 
+1

Спасибо. Несмотря на то, что ваш ответ не помог решить мою проблему, он предоставил важный ключ для его решения (см. Мой ответ). – Alexey

0

Я был успешным использованием более простой метод, чем то, что ОП предлагает в self-answer. Я производить URL-адреса с помощью:

new URL(scriptURL, window.location.href).toString(); 

где scriptURL является URL, который должен быть закреплен, чтобы получить нужный протокол и window является родителем из iframe элемента, который содержит сценарии. Это может позаботиться о сценариях, которые отличаются от URL-адресов OPs: например относительных URL-адресов (../foo.js) или абсолютных URL-адресов, которые не запускаются с хоста (/foo.js). В моем случае этого кода достаточно.

Если бы я повторил поиск по иерархии окон, который использовал OP, я бы, вероятно, сделал бы что-то вроде следующего. Это код TypeScript. Измените аннотации типа, чтобы получить простой 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. В моей настройке было что-то не так.

Смежные вопросы