跨源 iframe 中的 JavaScript 对话框 alert()、confirm() 和 prompt() 不再起作用 提交功能请求:提交的错误:解决方法:相关问题:

如何解决跨源 iframe 中的 JavaScript 对话框 alert()、confirm() 和 prompt() 不再起作用 提交功能请求:提交的错误:解决方法:相关问题:

Apps 脚本网络应用程序在 <iframe> 中工作。 Chrome 似乎不再支持 Alert()、Confirm(),在 web 应用上推广这些功能。

有什么解决办法吗?

  • Chrome 版本 92.0.4515.107(官方版本)(64 位) -- 不起作用
  • Edge 版本 91.0.864.71(官方版本)(64 位) -- 有效

尝试将 alert() 替换为 window.alert(),但仍然无效。

exec:1 一个不同的源子框架试图创建一个 JavaScript 对话框。这不再被允许并被阻止。有关详情,请参阅 https://www.chromestatus.com/feature/5148698084376576

解决方法

Google 为跨源 iframe 删除 alert()、confirm() 和 prompt() 是荒谬和主观的决定。他们称之为“功能”。理由很差 - 请参阅下面的“动机”。删除如此重要功能的一个非常薄弱的​​理由!社区和开发者应该抗议!

问题

https://www.chromestatus.com/feature/5148698084376576

功能:删除 alert()、confirm() 和跨源 iframe 提示

Chrome 允许 iframe 触发 Javascript 对话框,当 iframe 与顶部框架位于同一原点时,它会显示“say ...”,当 iframe 交叉时显示“该页面上的嵌入页面说...”起源。当前的用户体验令人困惑,并且之前曾导致网站假装消息来自 Chrome 或其他网站的欺骗行为。取消对跨源 iframe 触发 UI 功能的支持将防止这种欺骗行为,并阻止进一步的 UI 简化。

动机

JS 对话框的当前 UI(一般来说,不仅仅是跨域子框架的情况)令人困惑,因为消息看起来像浏览器自己的 UI。这导致了欺骗(尤其是 window.prompt),其中站点假装特定消息来自 Chrome(例如 1,2,3)。 Chrome 通过在消息前加上“say...”来缓解这些欺骗行为。然而,当这些警报来自跨域 iframe 时,UI 会更加混乱,因为 Chrome 试图解释对话框不是来自浏览器本身或顶级页面。鉴于跨源 iframe JS 对话框的使用率较低,事实上,当使用 JS 对话框时,站点的主要功能通常不需要它们,并且难以可靠地解释对话框的来源,我们建议删除 JS 对话框跨域 iframe。这也将取消阻止我们通过删除主机名指示并通过将对话框移动到内容区域的中心使对话框更明显地成为页面(而不是浏览器)的一部分来进一步简化对话框的能力。这些更改在移除对 JS 对话框的跨源支持时被阻止,否则这些子框架可能会假装它们的对话框来自父页面。

解决方案

通过 Window.postMessage() 从 iframe 向父级发送消息并通过父级页面显示对话框。这是谷歌上非常优雅的黑客和耻辱,因为在 Chrome 92 版客户端看到警报对话框之前,例如An embedded page iframe.com" says: ...(这是正确的 - 客户端看到调用警报的真实域)但现在使用 postMessage 解决方案客户端将看到一个谎言,例如The page example.com" says: ... 但 example.com 未调用警报。愚蠢的谷歌决定导致他们达到相反的效果 - 客户现在会更加困惑。谷歌的决定是仓促的,他们没有考虑后果。在 prompt() 和 confirm() 的情况下,通过 Window.postMessage() 有点棘手,因为我们需要将结果从顶部发送回 iframe。

谷歌接下来会做什么?禁用 Window.postMessage()?似曾相识。我们又回到了 Internet Explorer 时代……开发人员通过进行愚蠢的黑客攻击来浪费时间。

TL;DR:演示

https://domain-a.netlify.app/parent.html

代码

使用下面的代码,您可以在跨源 iframe 中使用覆盖的本机 alert()、confirm() 和 prompt(),代码更改最少。 alert() 的用法没有变化。我在confirm() 和prompt() 的情况下只需在它之前添加“await”关键字,或者随意使用回调方式,以防您无法轻松地将同步功能切换到异步功能。请参阅下面 iframe.html 中的所有使用示例。

坏事有好有坏 - 现在我通过这个解决方案获得了一个优势,即 iframe 域不会被显示(地址栏中的域现在在对话框中使用)。

https://example-a.com/parent.html

<!doctype html>
<html>
    <head>
        <meta charset="utf-8">
        <title>Parent (domain A)</title>
        <script type="text/javascript" src="dialogs.js"></script>
    </head>
    <body>
        <h1>Parent (domain A)</h1>
        <iframe src="https://example-b.com/iframe.html">
    </body>
</html>

https://example-b.com/iframe.html

<!doctype html>
<html>
    <head>
        <meta charset="utf-8">
        <title>Iframe (domain B)</title>
        <script type="text/javascript" src="dialogs.js"></script>
    </head>
    <body>
        <h1>Iframe (domain B)</h1>
        <script type="text/javascript">
            alert('alert() forwarded from iframe.html');
            
            confirm('confirm() forwarded from iframe.html via callback',(result) => {
                console.log('confirm() result via callback: ',result);
            });

            prompt('prompt() forwarded from iframe.html via callback',null,(result) => {
                console.log('prompt() result via callback: ',result);
            });
            
            (async () => {
                var result1 = await confirm('confirm() forwarded from iframe.html via promise');
                console.log('confirm() result via promise: ',result1);

                var result2 = await prompt('prompt() forwarded from iframe.html via promise');
                console.log('prompt() result via promise: ',result2);
            })();
        </script>
    </body>
</html>

dialogs.js

(function() {

    var id = 1,store = {},isIframe = (window === window.parent || window.opener) ? false : true;

    // Send message
    var sendMessage = function(windowToSend,data) {
        windowToSend.postMessage(JSON.stringify(data),'*');
    };

    // Helper for overridden confirm() and prompt()
    var processInteractiveDialog = function(data,callback) {
        sendMessage(parent,data);

        if (callback)
            store[data.id] = callback;
        else
            return new Promise(resolve => { store[data.id] = resolve; })
    };

    // Override native dialog functions
    if (isIframe) {
        // alert()
        window.alert = function(message) {
            var data = { event : 'dialog',type : 'alert',message : message };
            sendMessage(parent,data);
        };

        // confirm()
        window.confirm = function(message,callback) {
            var data = { event : 'dialog',type : 'confirm',id : id++,message : message };
            return processInteractiveDialog(data,callback);
        };

        // prompt()
        window.prompt = function(message,value,type : 'prompt',message : message,value : value || '' };
            return processInteractiveDialog(data,callback);
        };
    }

    // Listen to messages
    window.addEventListener('message',function(event) {
        try {
            var data = JSON.parse(event.data);
        }
        catch (error) {
            return;
        }

        if (!data || typeof data != 'object')
            return;

        if (data.event != 'dialog' || !data.type)
            return;

        // Initial message from iframe to parent
        if (!isIframe) {
            // alert()
            if (data.type == 'alert')
                alert(data.message)

            // confirm()
            else if (data.type == 'confirm') {
                var data = { event : 'dialog',id : data.id,result : confirm(data.message) };
                sendMessage(event.source,data);
            }

            // prompt()
            else if (data.type == 'prompt') {
                var data = { event : 'dialog',result : prompt(data.message,data.value) };
                sendMessage(event.source,data);
            }
        }

        // Response message from parent to iframe
        else {
            // confirm()
            if (data.type == 'confirm') {
                store[data.id](data.result);
                delete store[data.id];
            }

            // prompt()
            else if (data.type == 'prompt') {
                store[data.id](data.result);
                delete store[data.id];
            }
        }
    },false);

})();
,

到目前为止,唯一的“解决方案”是将以下内容添加到您的 Chrome/Edge 浏览器快捷方式:

--disable-features="SuppressDifferentOriginSubframeJSDialogs"

或降级您的浏览器。显然,这两者都不是理想的。谷歌真的很努力地把我们从这里拯救出来。

,

提交功能请求:

考虑使用此问题跟踪器 template 提交功能请求。

我要么请求为 Apps Script Web 应用程序设置例外,要么添加 alertconfirm 的内置方法,类似于现有的 alertprompt 对话框,目前适用于 Google 编辑器。

提交的错误:

顺便说一句,此行为已在问题跟踪器中报告(作为错误):

为了跟踪它,我会考虑 starring it

解决方法:

同时,正如其他人所说,考虑降级或更改浏览器,或使用以下命令行标志执行它:

--disable-features="SuppressDifferentOriginSubframeJSDialogs"

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-
参考1 参考2 解决方案 # 点击安装源 协议选择 http:// 路径填写 mirrors.aliyun.com/centos/8.3.2011/BaseOS/x86_64/os URL类型 软件库URL 其他路径 # 版本 7 mirrors.aliyun.com/centos/7/os/x86
报错1 [root@slave1 data_mocker]# kafka-console-consumer.sh --bootstrap-server slave1:9092 --topic topic_db [2023-12-19 18:31:12,770] WARN [Consumer clie
错误1 # 重写数据 hive (edu)&gt; insert overwrite table dwd_trade_cart_add_inc &gt; select data.id, &gt; data.user_id, &gt; data.course_id, &gt; date_format(
错误1 hive (edu)&gt; insert into huanhuan values(1,&#39;haoge&#39;); Query ID = root_20240110071417_fe1517ad-3607-41f4-bdcf-d00b98ac443e Total jobs = 1
报错1:执行到如下就不执行了,没有显示Successfully registered new MBean. [root@slave1 bin]# /usr/local/software/flume-1.9.0/bin/flume-ng agent -n a1 -c /usr/local/softwa
虚拟及没有启动任何服务器查看jps会显示jps,如果没有显示任何东西 [root@slave2 ~]# jps 9647 Jps 解决方案 # 进入/tmp查看 [root@slave1 dfs]# cd /tmp [root@slave1 tmp]# ll 总用量 48 drwxr-xr-x. 2
报错1 hive&gt; show databases; OK Failed with exception java.io.IOException:java.lang.RuntimeException: Error in configuring object Time taken: 0.474 se
报错1 [root@localhost ~]# vim -bash: vim: 未找到命令 安装vim yum -y install vim* # 查看是否安装成功 [root@hadoop01 hadoop]# rpm -qa |grep vim vim-X11-7.4.629-8.el7_9.x
修改hadoop配置 vi /usr/local/software/hadoop-2.9.2/etc/hadoop/yarn-site.xml # 添加如下 &lt;configuration&gt; &lt;property&gt; &lt;name&gt;yarn.nodemanager.res