业务是这样的
我们用 iframe 调用了 [被调用方] 的页面,然后 [被调用方] 页面一些 a 标签的 target 是“blank”的,这就导致点击他们的 a 标签会打开新的 tab
而现在的需求是,在 iframe 里的任何操作,都 [ [不允许弹出新 tab 或者新窗口] ] ,如果 [被调用方] 的页面的确是要打开新 tab 的,那就改为在本地页面跳转。
正常来说是无法实现的,因为跨域,而且 [被调用方] 肯定不会改代码的,所以只能写了个浏览器插件,通过注入代码的形式强行把网页里所有的 a 标签的 target 改为 self,这样 a 标签就全都是本地跳转
但是 [被调用方] 网页里面的业务不一定全是用 a 标签来打开新 tab,他们可能一些业务是用 js 来打开新 tab 的(类似于 window.open 这种,我尝试在插件里把 window.open 覆写成 window.location.href,但也只是部分按钮实现了,有些还是会跳出新页面)
现在问题如下: 1.被调用方是肯定不会改代码的,这个无解
2.已经能通过写浏览器插件的方式来注入代码强改客户代码的 a 标签(因为被调用方是不同域的,而且非互联网项目,装插件的设备也就那么几台,也不麻烦)
3.不能说这玩意不能做,因为项目跑在超高分大屏(电影院银幕大小)上,网页全屏显示,他有这种需求是因为打开新 tab 会强制关掉网页全屏,导致观感不好
然后如何完美实现??(虽然以我的见解这玩意是无法实现的,用浏览器插件来搞已经很仁至义尽了)
1
SlipStupig 2021-02-02 16:03:57 +08:00 3
父页面往子页面做事件注入,监听点击事件并且 Hook 掉一些事件和函数,在父页面创建一个事件监听器,然后定义一个 receiveMessage 函数,子页面通过 window.postMessage 做跨域通信,父页面就能知道具体的点击事件了,新 tab 可以先请求页面然后覆盖掉原始的 body,这要不用跳转直接刷新了,思路仅供参考哈
|
2
Osk 2021-02-02 16:04:05 +08:00 via Android
chrome 的 --kiosk 模式试试?
|
3
tanranran 2021-02-02 16:09:51 +08:00
写个浏览器的壳?
|
4
cheng6563 2021-02-02 16:13:36 +08:00
服务端也可以搞个[被调用方] 的代理程序,然后注入代码。可能比浏览器插件好用点?
|
5
meepo3927 2021-02-02 16:14:52 +08:00
用 Electron ? 没实践过,只是提供一个思路。
或者 nginx 做代理,把 iframe 代理到 [被调用方] 的域上,这样 iframe 就是同域了,不知能否解决。 |
6
yoshiyuki 2021-02-02 16:36:29 +08:00
nginx 或者 nodejs 来代理被调用页面,使用 replace 把 target 替换掉
|
7
biguokang OP @SlipStupig 一开始和你想法一样,但是实际项目情况,注入不了,因为子页面是跨域的,contentDocoument 是 null 的,直接操作 contentWindow 直接报跨域错误,所以后来才想着写浏览器插件来注入代码才改的了子页面的逻辑。。。。。而且你想使用 postMessage 来通信,需要改被调用方的代码来接收的,但是实际场景被调用方的代码他们是不能改的。。。。如果可以改被调用方的业务代码,也不会有那么多事了
|
8
zenxds 2021-02-02 16:41:13 +08:00
有些还是会跳出新页面?要具体看下有些是什么情况,比如 document.createElement 创建的 a 标签,需要把 document.createElement 也重写了
|
9
mknightoy 2021-02-02 16:43:27 +08:00
浏览器关掉跨域保护不就完了么,反正都是展示用的不需要跨域保护
|
10
SlipStupig 2021-02-02 16:56:31 +08:00
@biguokang 关闭浏览器的跨域选项或者用 Nginx 做代理,都可以啊
|
11
agee 2021-02-02 17:15:30 +08:00
自己做个套壳浏览器,就可以自己处理所有打开新窗口事件,这样不需要管网页上的代码了。理论上好像是这样,没具体试过。
|
12
winterx 2021-02-02 17:19:22 +08:00 2
难道就只有我想知道为什么被调用方不肯改代码?
|
13
SakuraKuma 2021-02-02 17:21:48 +08:00
支持 nginx 反代,把 target 都干掉
除非额外有骚操作 js 跳转之类的 |
15
stillyu 2021-02-02 18:09:34 +08:00
设置浏览器禁止打开弹出窗口?
|
16
DrakeXiang 2021-02-02 18:17:46 +08:00
有浏览器扩展强制在同一个 tab 打开新页面
|
17
SystemLight 2021-02-02 19:19:42 +08:00
为什么不把 iframe 中内容读取出来,然后动态修改里面内容 再呈现呢 ?
|
18
msmmbl 2021-02-02 20:18:11 +08:00 via Android
可以用 nw.js 的话,他有一个 new-win-policy 和 navigation 事件可以控制跳转行为。
|
19
leo108 2021-02-02 20:27:20 +08:00
window.open = function(url) { location.href = url }
window.open('https://v2ex.com') |
20
ciqulover 2021-02-02 20:35:21 +08:00 via iPhone
既然都有浏览器插件了 咋还动不了 iframe 跳转逻辑呢?直接 intercept 掉 iframe 内的 script 加载返回体,正则全局替换 window.open,如果内联在 html 里的 script 代码,用 mutation observer 劫持替换就行。
|
21
musi 2021-02-02 23:40:26 +08:00 via iPhone 2
其实 iframe 还有个 sandbox 属性可以设置 allow-popups
详情左转 https://developer.mozilla.org/zh-cn/docs/web/html/element/iframe |
22
Hanada 2021-02-03 00:01:15 +08:00
为什么不考虑一下直接反向代理被调用方的网页,然后就可以根据需要进行改动了
|
23
zqx 2021-02-03 06:51:08 +08:00 via Android
避免 iframe 的安全策略,就肯定不能用 iframe 了。
可以在你的 js 里,把别人的 html 请求回来,解析并插入到自己的 DOM 中,再请求 css js,是 vue 或 react 或原生 js,按对应的逻辑执行。关键难点在于要拿到他的路由和状态管理,如果他没有在代码里显式导出给你,就很难拿到,需要从源码里找 微前端的实现大概也是这个思路 |
24
sampeng 2021-02-03 08:17:01 +08:00 via iPhone
这你都干…怼回去啊。怎么不让做个屏幕随着衣服颜色变色呢?
|
25
uiosun 2021-02-03 08:26:07 +08:00
iframe 不是可以禁止跳转吗……就在基本配置里啊……
是我没理解对需求,还是你好歹去看看文档啊…… |
26
zhw2590582 2021-02-03 09:35:29 +08:00
Chrome 可以监听新页面打开事件,看能不能在打开的时候马上关闭,并 iframe 重定向
|
27
duduaba 2021-02-03 09:51:25 +08:00
iframe sandbox 属性,但是 ie9 前是不支持的。
|
28
GM 2021-02-03 10:24:43 +08:00
自己写一个程序,内嵌 webview,不要用第三方浏览器,这样有 100%的控制权,随便搞。
|
29
biguokang OP @uiosun 老哥,我当然知道 iframe 是可以通过设置 sandbox 来禁止跳转,这个不用你教。。。问题是我的需求不是禁止跳转,而是把打开新窗口的逻辑改为在原地跳转
|
30
biguokang OP @coderfuns 这玩意我是有设置的,唯一的作用也就是禁止 iframe 页面打开新窗口而已,只不过满足不了需求,需求是把打开新窗口的操作变为原地跳转
|
31
biguokang OP @musi 这玩意我是有设置的,唯一的作用也就是禁止 iframe 页面打开新窗口而已,只不过满足不了需求,需求是把打开新窗口的操作变为原地跳转
|
32
biguokang OP @ciqulover 我是自己开发了一个浏览器插件,通过注入的方式解决了,说白了就是通过事件委托检测到点击了 a 标签后,然后禁止调 a 标签的行为,改为 window.location.href=xxx 就实现了。。。但只是解决了 a 标签的跳转逻辑,而 js 的跳转还没有
|
33
shaoyijiong 2021-02-03 10:32:30 +08:00
我们有一个类似的需求 我们是在后端写一个代理服务 , 前端请求那个代理 , 代理请求对应的网页 ; 然后在代理服务里面写入自己的 js 代码 , 就可以修改原来的 html 元素里面的 a 标签了 ; 或者直接修改原始 html 也行
后端使用的是 java 做的代理 https://github.com/mitre/HTTP-Proxy-Servlet |
34
shaoyijiong 2021-02-03 10:40:51 +08:00
也可以在嵌入的 js 中取消别人的点击事件
|
35
no1xsyzy 2021-02-03 10:59:23 +08:00
用 Nginx 反代改成同域啊
Aria2 的老技巧了( |
36
dlllcs 2021-02-03 11:14:47 +08:00
electron 可解
|
37
ArthurSS 2021-02-03 11:15:21 +08:00
https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/iframe
sandbox 该属性对呈现在 iframe 框架中的内容启用一些额外的限制条件。属性值可以为空字符串(这种情况下会启用所有限制),也可以是用空格分隔的一系列指定的字符串。有效的值有: ... allow-popups: 允许弹窗 (例如 window.open, target="_blank", showModalDialog)。如果没有使用该关键字,相应的功能将自动被禁用。 ... |
38
mxT52CRuqR6o5 2021-02-03 11:17:10 +08:00
不能改代码,那能不能看代码,遇到没拦截住的就具体看看代码里是咋跳的,就知道为啥没拦截到了
|
40
krapnik 2021-02-03 11:55:25 +08:00
19 楼的方法解决不了嘛?
|
41
CODEWEA 2021-02-03 12:56:08 +08:00
我做过类似的,用 postMessage 通信即可
|
42
lixiangzaizheli 2021-02-03 13:19:39 +08:00
重写跳转注入不就好了
|
43
ganbuliao 2021-02-03 13:21:33 +08:00
解决办法就是 : 劫持注入 js ,插件注入 js,套壳写浏览器,
|
45
biguokang OP @mxT52CRuqR6o5 被调用方的代码是 webpack 打包过的,变量名也被打包工具魔改了,基本无可读性
|
46
PineappleBeers 2021-02-03 15:16:36 +08:00
我觉得你当前的需求用 4 楼和 19 楼的方法结合就来就可以解决。
浏览器请求你的服务。 服务从被调用方的地址获取到页面。 从获取到的 html 里注入一个 script 标签,标签里的内容就是重写 window.open 。 然后将注入后的页面返回浏览器。 |
47
biguokang OP @PineappleBeers 他们可能没看完我的问题,我问题里说了已经我已经 override 了 window.open,但也只是一部分生效而已。。。而且所有的 a 标签已经被我的注入代码改成 target=_self 了
|
48
zhuweiyou 2021-02-03 17:42:07 +08:00
被调用方的页面 用服务端代理 + 改写
|
49
R18 2021-02-03 17:48:05 +08:00 via Android
制作专用的浏览器呢?
|
50
autoxbc 2021-02-04 04:29:09 +08:00
并不需要读懂对方代码,只要把能够进行地址跳转的函数全部覆盖一遍,大概一只手就能数过来
|
51
billccn 2021-02-04 05:59:33 +08:00
想到我十年前做的老项目,当时是为一个触摸屏的工业设备做一些辅助功能,公司不想花钱去买厂家的 SDK,就要求利用内置的浏览器实现,最骚的就是偶尔要内嵌显示另一个网站,要可以交互,但是不能允许该网站弹窗或者影响宿主页面,这些是 iframe 做不到的(有这些功能那机子的内存也不够)。
最后发现那个内置的浏览器可以支持 Java applets,就直接在网页里套了个 Java 版的 VNC 客户端,连接到服务器上一个无壳的 Chrome,弹窗什么的都只在服务器上进行,怎么也不会影响到客户端,而且客户端可以看到所有的效果。现在时代进步了,VNC 客户端可以直接用 JS 实现了。 |