【问题标题】:How to override JavaScript alert function inside an iframe before it finished loading?如何在 iframe 完成加载之前覆盖其内的 JavaScript 警报功能?
【发布时间】:2019-06-06 16:10:30
【问题描述】:

我正在使用带有 wraith(https://github.com/BBC-News/wraith) 的 headless chrome 浏览器问题是我的页面打开 alert wraith 失败

ERROR: unexpected alert open: {Alert text : Bla bla bla.}
  (Session info: headless chrome=71.0.3578.98)
  (Driver info: chromedriver=71.0.3578.33 (269aa0e3f0db08097f0fe231c7e6be200b6939f7),platform=Mac OS X 10.13.6 x86_64)

这是我尝试过的,但到目前为止失败了:

const BACKEND_USERNAME = "";
const BACKEND_PASSWORD = "";

function resizeIFrameToFitContent(iFrame) {
    iFrame.width = iFrame.contentWindow.document.body.scrollWidth;
    iFrame.height = iFrame.contentWindow.document.body.scrollHeight;
}


var original_url_asked = document.referrer;
if (typeof jQuery !== 'undefined') {//maybe 500 or 404 page
    $(document).ready(function () {
        //we ended up on login page, let's login
        $('body > div:nth-child(23) > div.backend_right_content > div > div > form > input[type="password"]:nth-child(3)').prop('value', BACKEND_PASSWORD);
        $('body > div:nth-child(23) > div.backend_right_content > div > div > form > input[type="text"]:nth-child(1)').prop('value', BACKEND_USERNAME);
        $('body > div:nth-child(23) > div.backend_right_content > div > div > form > input[type="submit"]:nth-child(5)').click();//submit form

        //we are logged in
        $('body').empty();//clear all the stuff
        //since we can't redirect, we'll open a full page iframe with the url we wanted to see initially
        $('body').append('<iframe id="ifr" width="100%" height="100%" frameborder="0" src="" ></iframe>');

        //load the original_url finally
        $("#ifr").attr("src", original_url_asked);//cannot redirect or wraith complains


        //hide the menu and other elements, for smaller screenshots
        $('#ifr').on('load', function () {
            $('#ifr').contents().find('div.backend_left, div.backend_right_top').remove();
            resizeIFrameToFitContent(document.getElementById('ifr'));
        });
    });
}

//important or wraith will not understand it is ready to take a screenshot
var callback = arguments[arguments.length - 1];
setTimeout(callback, 20000);//wait for page to load

【问题讨论】:

  • 到目前为止失败是什么意思?有什么错误吗?
  • @TomM 好吧,我想他仍然有 wraith 产生的相同错误,因此他的尝试失败了...... :-)
  • @IslamElshobokshy 是的,这是有道理的。
  • 在设置 'src' 属性之前,您是否尝试设置 iframe.contentWindow.alertiframe.contentWindow.prototype.alert
  • 你确定它是alert 而不是confirm

标签: javascript html google-chrome iframe overriding


【解决方案1】:

如果您可以访问跨域 iframe,那么您可以覆盖原生 alert 函数,如下所示:

<iframe id="ifr" src="about:blank"></iframe>
<script type="text/javascript">
var iframe = document.getElementById('ifr');

iframe.addEventListener('load', function(event)
{
    iframe.contentWindow.alert = function(s){console.log(s)};
});

iframe.src = 'iframe.html';
</script>

来自iframe.html的代码

<script type="text/javascript">
alert('iframe'); // this will always native function and you can not override it
</script>

<!-- BUT the following message you will get in console: -->
<input type="button" value="try it" onclick="alert('Your native alert was overriden!')">

现在您可以单击此 iframe 中的按钮,您将在控制台中收到消息 'Your native alert was overriden!'

换句话说:您可以覆盖本机 alert 函数,但您无法在 iframe window 加载之前覆盖它。我们没有针对这种情况的事件。只有在加载 iframe window 后,您才能使用覆盖的功能。如果对你来说足够了,那么你可以使用它。

但还有一些你不能做的事情。

了解的重点:

从新的src 为您的 iframe 设置后,iframe 将加载原始(本机)alert 函数。因此,您必须在 iframe 中的新网站加载后始终覆盖它。

替代解决方案

感谢用户 Munim Munna 在评论中的提示,我们有一个完美的解决方案: 您可以将 sandbox="allow-forms allow-same-origin allow-scripts" 作为属性添加到您的 iframe,如下所示:

<iframe id="ifr" src="about:blank" sandbox="allow-forms allow-same-origin allow-scripts"></iframe>

除非您将allow-modals 添加到此列表,否则所有警报框都将被忽略。在这种情况下,您将在控制台中收到一条错误消息:

忽略对'alert()' 的调用。该文档已被沙盒化,并且未设置“allow-modals”关键字。

如果有人不喜欢它,那么他可以像我的回答的第一部分一样覆盖alert 函数。

【讨论】:

    【解决方案2】:

    您无法使用 JavaScript 阻止警报窗口,因为当 wraith 执行 before_capture 脚本时,警报弹出窗口已经存在。因此,当wraith 尝试执行 JavaScript 并打开警报弹出窗口时,webdriver 会引发您遇到的错误。

    你可以切换到phantomjs来解决这个问题,但是如果你想坚持使用selenium headless chrome和wraith,你必须修补wraith才能正确处理模态弹出窗口。

    文件:{Ruby 安装目录}\lib\ruby\gems\2.6.0\gems\wraith-4.2.3\lib\wraith\save_images.rb
    :129

    driver.navigate.to url
    # patch to handle rogue alert popups at page load
    while true
      begin
        driver.switch_to.alert.dismiss
      rescue
        break
      end
    end
    # patch end
    driver.execute_async_script(File.read(global_before_capture)) if global_before_capture
    

    当页面导航到您的 URL 时,while 循环将关闭它发现的尽可能多的警报弹出窗口,然后运行 ​​before_capture 脚本。

    【讨论】:

    • phantomJs 和类似的不起作用,请参阅 github.com/BBC-News/wraith/issues/508#issuecomment-351072629 ,我尝试了您的代码,但问题是我首先登录,然后在重定向后打开预期的页面,所以补丁可能有效,但是不是我的情况:/
    • 您如何登录?使用before_capture 脚本?能否提供流程的代码示例?
    • 是的,使用 before_capture 脚本,请看我的问题,我已经更新了 js 代码,谢谢
    • 在这种情况下,只需将sandbox="allow-forms allow-same-origin allow-scripts" 属性添加到您的iframe。除非您向其中添加 allow-modals,否则所有警报调用都将被忽略。您仍然可以将警报调用转储到控制台。
    • 完美,我将不得不用谷歌搜索它为什么可以工作:D,它可以在没有补丁的情况下工作
    猜你喜欢
    • 1970-01-01
    • 2010-12-16
    • 1970-01-01
    • 2015-01-17
    • 1970-01-01
    • 1970-01-01
    • 2017-07-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多