3

iframe 与父页面交互

父页面与 iframe 交互

/**
 * 父页面获取 iframe window 对象
 */
const iframeWin = document.getElementById("iframe").contentWindow;
const iframeWin = document.getElementsByTagName('iframe')[0].contentWindow;
/**
 * 父页面获取 iframe document 对象
 */
const iframeDoc = iframeWin.document;
/**
 * 父页面获取 iframe body 对象
 */
const iframeBody = iframeDoc.body;
/**
 * 父页面调用 iframe 方法
 */
iframeWin.method(); // method 是 iframe 的一个方法名

iframe 与父页面交互

/**
 * iframe 获取父页面 window 对象
 */
const parentWin = window.parent;
/**
 * iframe 获取父页面 document 对象
 */
const parentDoc = window.parent.document;
/**
 * iframe 获取父页面 window 对象
 */
const parentBody = window.parent.body;
/**
 * iframe 调用父页面的方法
 */
window.parent.method(); // method 是父页面的方法

iframe 与父页面之间传递数据

window.postMessage是允许两个(跨域)窗口或 iframes 发送数据信息。像是跨域的AJAX,但不是浏览器跟服务器之间交互,而是在两个客户端之间通信。更多信息查看 window.postMessage

发送消息:

/**
 * iframe 页面发送消息
 */
const message = 'Hello!'; // 发送到其他 window的数据
const domain = '*'; // 指定哪些窗口能接收到消息事件,‘*’表示无限制
window.postMessage(message, domain); 

接收消息:

/**
 * data: 发送方窗口发送的数据
 * origin: 发送方窗口的 origin 
 * source: 发送消息的窗口对象的引用
 */
window.addEventListener('message', (event) => {
  const { data, origin, source } = event
  console.log(event)
}, false);

嵌套多个 ifream 跳转

背景
A, B, C, D 是四个页面,B 是 A 的 iframe,C 是 B 的 iframe,D 是 C 的 iframe。

问题
在 D 中跳转页面

跳转
使用 window.open() 是类似的。

/**
 * 在本页面跳转(D 页面跳转)
 */
window.location.href = '';
/**
 * 在上一层页面跳转(C 页面跳转)
 */
window.parent.location.href = '';
/**
 * 在上上一层页面跳转(B 页面跳转)
 */
window.parent.parent.location.href = '';
/**
 * 在最外层页面跳转(A 页面跳转)
 */
window.top.location.href = '';

链接或form

D 页面中有form

/**
 * form 提交后,在 D 页面跳转
 */
<form></form>
/**
 * form 提交后,弹出新页面
 */
<form target="_blank"></form>
/**
 * form提交后,在 C 页面跳转
 */
<form target="_parent"></form>
/**
 * form提交后,在 A 页面跳转
 */
<form target="_top"></form>

刷新

/**
 * C 页面刷新
 */
window.parent.location.reload();
/**
 * A 页面刷新
 */
window.top.location.reload();

Chrome 80 后无法携带 Iframe cookie

前言

从 Chrome 51 开始,浏览器的 HTTP响应头 Set-Cookie 新增加一个 SameSite 属性,该属性默认是关闭的。从 Chrome 80 之后,该属性默认开启。

SameSite
SameSite 属性:用来防止 CSRF 攻击和用户追踪。接受以下三个值:

属性值含义
Strict完全禁止第三方 Cookie。Cookies只会在第一方上下文中发送,不会与第三方网站发起的请求一起发送。跨站点时,任何情况下都不会发送 Cookie。
Lax浏览器中的默认值。Cookies 允许与顶级导航一起发送,并将与第三方网站发起的 GET 请求一起发送。顶级导航到目标网址的 GET 请求,只包括三种情况:链接,预加载请求,GET 表单iframeAJAXImage 是不会发送第三方 cookie 的。
NoneCookie将在所有上下文中发送,即允许跨域发送。

问题描述

在 iframe 中,即使 iframe 页面和 iframe 的服务器不存在跨域问题,但是当 iframe 发出请求时,iframe 的父级页面也就是当前网页的 URL 和请求目标并不同源,所以请求想要携带的 iframe 域下的 cookie 属于第三方 cookie,浏览器默认会禁止其携带。

解决方法

1. 修改浏览器 SameSite 属性【只针对于 Chrome 】

版本修改方法
Chrome 80 之前未设置SameSite,允许携带第三方 cookie
Chrome 80 - 90修改浏览器 flags 的两个属性:SameSite by default cookies、Cookies without SameSite must be secure
Chrome 91 - 93修改浏览器启动参数:SameSiteByDefaultCookies 和 CookiesWithoutSameSiteMustBeSecure
Chrome 94-

Chrome 80 - 90:

  1. 谷歌浏览器地址栏输入:chrome://flags/
  2. 找到:SameSite by default cookies、Cookies without SameSite must be secure
  3. 设置这两项为 Disable

Chrome 91之后

浏览器禁用了 flags 的same-site-by-default-cookiescookies-without-same-site-must-be-secure两个属性,所以不能在 flags 修改。但是可以通过修改启动 Chrome 所带的两个参数:SameSiteByDefaultCookiesCookiesWithoutSameSiteMustBeSecure来实现携带 cookie。

Windows 系统可以通过修改应用的快捷方式目标属性来给启动的应用加上参数:

  1. 右击 Chrome 的快捷方式,点击"属性"
  2. 在"目标(Target)"属性中末尾加上(需要空格): --disable-features=SameSiteByDefaultCookies,CookiesWithoutSameSiteMustBeSecure
  3. 重启浏览器(点击此快捷方式)

Mac 系统可以通过终端打开浏览器解决:

  1. 关闭浏览器
  2. 打开终端输入命令: open -a "Google Chrome" --args --disable-features=SameSiteByDefaultCookies,CookiesWithoutSameSiteMustBeSecure

Chrome 94

将会移除--disable-features=SameSiteByDefaultCookies,CookiesWithoutSameSiteMustBeSecure

2. 设置 Cookie

报文里面set-cookie,添加SameSite=None; Secure=true。host 必须是 https


时倾
791 声望2.4k 粉丝

把梦想放在心中