网站开发 都包含什么语言,中交建设招标有限公司网站,网站建设与维护难不难,如何在百度发布信息父子页面通信受限#xff1f;JS中iframe同源策略全解析与实战突破 父子页面通信受限#xff1f;JS中iframe同源策略全解析与实战突破引言#xff1a;为什么你的iframe操作总被浏览器“拒之门外”iframe到底是什么——前端开发者眼中的嵌入式窗口同源策略的前世今生#xff…父子页面通信受限JS中iframe同源策略全解析与实战突破父子页面通信受限JS中iframe同源策略全解析与实战突破引言为什么你的iframe操作总被浏览器“拒之门外”iframe到底是什么——前端开发者眼中的嵌入式窗口同源策略的前世今生浏览器为何如此“多疑”深入理解同源协议、域名、端口一个都不能少父子页面DOM互访的正确姿势仅限同源场景跨域时的典型报错现象与背后的安全逻辑postMessage跨域通信的官方“绿色通道”使用window.frames与contentWindow访问子页面DOM细节父页面如何安全地向iframe注入脚本或样式子页面主动与父页面对话的几种可靠方式避开CSP限制Content Security Policy对iframe的影响本地开发时file协议引发的“伪跨域”陷阱Nginx反向代理开发阶段绕过跨域限制的实用技巧动态创建iframe时的同源判断与异常处理iframe加载完成时机判断避免操作未就绪DOM调试技巧Chrome DevTools中如何审查跨iframe元素真实项目踩坑实录那些年我们被同源策略“教育”的瞬间提升健壮性封装通用的iframe通信工具函数性能考量频繁跨iframe通信带来的渲染开销未来可期Web Components是否能替代部分iframe场景父子页面通信受限JS中iframe同源策略全解析与实战突破引言为什么你的iframe操作总被浏览器“拒之门外”第一次把iframe嵌进页面的时候我以为自己只是“放了个小窗口”结果浏览器反手甩给我一句Uncaught DOMException: Blocked a frame with origin “https://a.com” from accessing a cross-origin frame.那一刻我深刻体会到什么叫“浏览器的高墙”。iframe就像一间玻璃房看得见却未必摸得着。今天我们就把这层玻璃砸个洞——合法地。iframe到底是什么——前端开发者眼中的嵌入式窗口别被“iframe”四个字母吓到它本质上就是浏览器给你开的一个“画中画”一个完全独立的浏览上下文有独立的window、document、cookie、甚至console。你可以把它当成“页面里的页面”只不过这个页面要么和你同穿一条裤子同源要么来自隔壁老王家跨域。同穿裤子好说话隔壁老王就得按规矩递纸条postMessage。同源策略的前世今生浏览器为何如此“多疑”1995 年 Netscape 的工程师大概不会想到他们为了防“偷 cookie”的小手段三十年后仍让无数前端凌晨三点抱着键盘痛哭。同源策略Same-Origin Policy就是浏览器的“防盗门”协议、域名、端口三位密码对不上门就焊死。目的很单纯——防止恶意网站把支付宝的余额当 API 随便读。虽然严格但少了它Web 世界早被薅成葛优。深入理解同源协议、域名、端口一个都不能少规则简单粗暴却常有人踩坑父页面 URLiframe URL是否同源原因https://a.com:443https://a.com:443/child✅完全一致https://a.comhttp://a.com❌协议不同https://a.com:443https://a.com:8443❌端口不同https://a.comhttps://sub.a.com❌域名不同本地开发最容易翻车的是file://协议——每个本地 HTML 都算不同源后面会单独吐槽。父子页面DOM互访的正确姿势仅限同源场景如果确认“同穿一条裤子”直接把手伸过去就行!-- parent.html 位于 https://a.com --iframeidsonsrchttps://a.com/son.html/iframescript// 1. 获取子窗口constsondocument.getElementById(son).contentWindow;// 或 window.frames[0]// 2. 读 DOMson.document.body.style.backgroundpapayawhip;// 改背景console.log(son.document.title);// 读标题// 3. 注入脚本constscriptson.document.createElement(script);script.textContentconsole.log(I am injected by Dad!);son.document.head.appendChild(script);// 4. 调用子页面全局函数son.sayHi();// son.html 里得先定义 window.sayHi () alert(Hi)/script子页面也能反向拿捏父页面!-- son.html 位于 https://a.com --script// 1. 父窗口句柄constdadwindow.parent;// 2. 操作父 DOMdad.document.titleSon says hello;// 3. 调用父页面方法dad.dadFunction();// parent.html 里得先定义 window.dadFunction/script跨域时的典型报错现象与背后的安全逻辑一旦跨域浏览器立刻翻脸。常见三杀Blocked a frame with origin ... from accessing a cross-origin frame.Permission denied to access property ...SecurityError: Failed to read a named property ...背后逻辑一句话任何可能泄露用户隐私的跨源读操作通通禁止。写操作也被限制但图片、CSS 这类“资源嵌入”默认放行——毕竟只是展示不暴露数据。postMessage跨域通信的官方“绿色通道”浏览器把门焊死却留了个“小窗”——window.postMessage。语法朴实无华却能跨源传纸条// 父页面向子 iframe 发消息constsondocument.querySelector(iframe).contentWindow;son.postMessage({type:greeting,payload:Hello Son},https://b.com);子页面监听// son.html 位于 https://b.comwindow.addEventListener(message,e{// 1. 先校验来源防止隔壁老王冒充if(e.origin!https://a.com)return;// 2. 读取数据console.log(e.data);// {type: greeting, payload: Hello Son}// 3. 回信e.source.postMessage({type:reply,payload:Got it, Dad!},e.origin);});父页面收信window.addEventListener(message,e{if(e.origin!https://b.com)return;console.log(Son says:,e.data.payload);// Got it, Dad!});注意第二个参数targetOrigin千万别用*除非你想上安全漏洞头条。数据会被结构化克隆函数、DOM 节点、Symbol 无法传递想传函数请用字符串 eval不推荐风险自理。使用window.frames与contentWindow访问子页面DOM细节iframe.contentWindow返回的是子窗口的window对象而iframe.contentDocument返回document对象。二者同源时想怎么玩都行constiframedocument.getElementById(map);constidociframe.contentDocument||iframe.contentWindow.document;idoc.open();idoc.write(h1Dynamic Content/h1);idoc.close();跨域时这两个属性直接抛出SecurityError别挣扎。父页面如何安全地向iframe注入脚本或样式同源场景直接appendChild即可。跨域只能让子页面自己“主动”拉取。思路父页面通过postMessage下发“配置”子页面监听后动态创建script/link标签把资源地址指向父页面下发的 CDN 地址子页面自行执行父页面零接触避免跨域。示例// parent.htmlson.postMessage({type:inject,css:https://cdn.a.com/theme/dark.css,js:https://cdn.a.com/plugin/chart.js},https://b.com);// son.htmlwindow.addEventListener(message,e{if(e.data.typeinject){if(e.data.css){constlinkdocument.createElement(link);link.relstylesheet;link.hrefe.data.css;document.head.appendChild(link);}if(e.data.js){constscriptdocument.createElement(script);script.srce.data.js;document.head.appendChild(script);}}});子页面主动与父页面对话的几种可靠方式除了postMessage同源时还能直接window.parent.xxx()。跨域则只剩两条路postMessage回信前面已讲。子页面通过top.postMessage向最顶层广播再由顶层转发。如果嵌套层级深建议封装“信使”// messenger.js 公共库classCrossMessenger{constructor(target,origin){this.targettarget;this.originorigin;this.id0;this.callbacksnewMap();window.addEventListener(message,this._handle.bind(this));}send(type,payload,transfer){constidthis.id;returnnewPromise(resolve{this.callbacks.set(id,resolve);this.target.postMessage({__id:id,type,payload},this.origin,transfer);});}_handle(e){const{__id,result}e.data;if(this.callbacks.has(__id)){this.callbacks.get(__id)(result);this.callbacks.delete(__id);}}}// 父页面constsondocument.querySelector(iframe).contentWindow;constmsgernewCrossMessenger(son,https://b.com);msger.send(add,{a:1,b:2}).then(resconsole.log(12,res));// 子页面constmsgernewCrossMessenger(window.parent,https://a.com);window.addEventListener(message,asynce{if(e.data.typeadd){constsume.data.payload.ae.data.payload.b;e.source.postMessage({__id:e.data.__id,result:sum},e.origin);}});避开CSP限制Content Security Policy对iframe的影响CSP 就像“第二把锁”。如果父页面响应头写了Content-Security-Policy: frame-src self https://safe.com;那么iframe srchttps://evil.com会被直接拦截连请求都不会发。还有child-src、default-src也能管 iframe。子页面自己也带 CSP 的话父页面想注入脚本也会吃瘪Content-Security-Policy: script-src self此时就算同源父页面也不能appendChild外联脚本。解决思路开发阶段用meta标签临时放宽生产环境把资源域名加入白名单用nonce-或sha256-给脚本签名。本地开发时file协议引发的“伪跨域”陷阱file:///C:/project/a.html打开页面再嵌套file:///C:/project/b.html浏览器会告诉你这是两个不同源因为路径算域名哪怕同一目录也算。解决用http-server/vite/webpack-dev-server起本地服务别双击 HTML。VSCode 的 Live Server 插件一键搞定。如果必须走file用postMessage通信但 Chrome 会强制targetOrigin*极不安全仅作调试。Nginx反向代理开发阶段绕过跨域限制的实用技巧后端不给 CORSNginx 一把梭# 把 /api 代理到后端 location /api { proxy_pass http://backend:8080; add_header Access-Control-Allow-Origin *; } # 把 /child 代理到另一个域 location /child { proxy_pass https://b.com/child; proxy_cookie_domain b.com localhost; # 保持 cookie }前端完全无感浏览器以为“同穿一条裤子”DOM 想摸就摸。注意生产环境别乱用容易把后端安全策略打穿。动态创建iframe时的同源判断与异常处理运行时创建 iframe要先判断 url 是否跨域functioncanAccess(url){constadocument.createElement(a);a.hrefurl;returna.protocollocation.protocola.hostnamelocation.hostnamea.portlocation.port;}constiframedocument.createElement(iframe);iframe.srcurl;document.body.appendChild(iframe);iframe.onload(){if(canAccess(url)){// 直接操作iframe.contentDocument.body.style.backgroundpink;}else{// 改用 postMessageiframe.contentWindow.postMessage({cmd:setBg,color:pink},url);}};iframe加载完成时机判断避免操作未就绪DOMiframe 的onload只代表主文档加载完不代表里面的脚本跑完。如果子页面是 React/Vue 单页需要子页面主动“报告”// son.htmlwindow.addEventListener(DOMContentLoaded,(){top.postMessage({type:ready},https://a.com);});父页面收到ready后再发业务指令避免“操作了空DOM”的惨案。调试技巧Chrome DevTools中如何审查跨iframe元素Elements 面板左上角“靶心”图标 → 点选 iframe 内元素DevTools 会自动切到对应 context。Console 切换执行环境下拉框选 iframe 的window再敲document就是子页面的。Network 面板勾选 “Use large request rows” “Preserve log”可追踪 iframe 发起的请求。Application → Frames查看每个 iframe 独立的 localStorage、cookie、sessionStorage。真实项目踩坑实录那些年我们被同源策略“教育”的瞬间埋点 SDK 嵌 iframe客户站点https://customer.com内嵌我们的https://log.com/iframe.html想拿parent.document.referrer上报结果直接抛 SecurityError。最后只能让后端在 URL 带上?refxxx。H5 支付后跳转微信返回页面在 iframe 内支付成功后需要通知顶层刷新。由于微信返回页是https://wx.tenpay.com与父页面不同源只能用postMessage但 iOS Safari 在微信内嵌浏览器里部分版本postMessage延迟高达 3 秒只能加 loading 动画“硬等”。本地开发用file://打开测试同事把打包好的 HTML 直接双击结果iframe.contentWindow全线阵亡还以为代码 bug折腾一下午。提升健壮性封装通用的iframe通信工具函数把前面CrossMessenger再升级支持超时、批量、心跳classRobustMessenger{constructor(target,origin,{timeout5000,heartbeat10000}{}){this.targettarget;this.originorigin;this.timeouttimeout;this.heartbeatheartbeat;this.pendingnewMap();this.heartbeatTimernull;this.startHeartbeat();}send(type,payload){constidMath.random().toString(36).slice(2);returnnewPromise((resolve,reject){consttimersetTimeout((){this.pending.delete(id);reject(newError(Request timeout));},this.timeout);this.pending.set(id,{resolve,timer});this.target.postMessage({__id:id,type,payload},this.origin);});}startHeartbeat(){this.heartbeatTimersetInterval((){this.send(__ping,{}).catch((){console.warn(Heartbeat failed, iframe may be crashed);});},this.heartbeat);}stopHeartbeat(){clearInterval(this.heartbeatTimer);}_handle(e){if(e.origin!this.origin)return;const{__id,result,error}e.data;constctxthis.pending.get(__id);if(ctx){clearTimeout(ctx.timer);this.pending.delete(__id);if(error)ctx.reject(newError(error));elsectx.resolve(result);}}}性能考量频繁跨iframe通信带来的渲染开销postMessage本质是一次结构化克隆 进程间通信高频调用如mousemove会挤占主线程。实测连续发送 1k 条 1KB 数据Chrome 占用 40% CPU帧率掉到 20fps。优化策略节流 合并50ms 一批数组打包Transferable Objects大数据用ArrayBuffer转移所有权零拷贝SharedArrayBuffer Atomics需跨线程同步但要求crossOriginIsolated配置麻烦必要时直接top.location.href #JSON.stringify(data)利用 hash 变化传递虽土但快。未来可期Web Components是否能替代部分iframe场景iframe 的最大痛点资源重复、SEO 不友好、通信麻烦。Web Components 的 Shadow DOM 提供了样式隔离Custom Elements 允许标签级复用看起来很美。但现实是主页面脚本仍然能shadowRoot.querySelector拿到内部 DOM安全隔离不如 iframe没有独立的windowcookie、localStorage 仍共享老旧浏览器IE11直接抬走。结论同域内、UI 组件级复用Web Components 可以干掉 iframe跨域、需要独立安全沙箱iframe 仍是爸爸。未来如果fencedframe、portal全面落地或许能再分一杯羹但眼下先把postMessage用熟不掉头发才是正经事。至此我们已把 iframe 的同源策略从“为什么”到“怎么办”拆了个底朝天。记住浏览器的高墙不是敌人而是守夜人。学会递纸条而不是抡大锤才能在前端这条路上走得稳、走得远。祝你下一次遇到SecurityError时不再怀疑人生而是微微一笑小样我懂你。欢迎来到我的博客很高兴能够在这里和您见面希望您在这里可以感受到一份轻松愉快的氛围不仅可以获得有趣的内容和知识也可以畅所欲言、分享您的想法和见解。推荐DTcode7的博客首页。一个做过前端开发的产品经理经历过睿智产品的折磨导致脱发之后励志要翻身农奴把歌唱一边打入敌人内部一边持续提升自己为我们广大开发同胞谋福祉坚决抵制睿智产品折磨我们码农兄弟专栏系列点击解锁学习路线(点击解锁知识定位《微信小程序相关博客》持续更新中~结合微信官方原生框架、uniapp等小程序框架记录请求、封装、tabbar、UI组件的学习记录和使用技巧等《AIGC相关博客》持续更新中~AIGC、AI生产力工具的介绍例如stable diffusion这种的AI绘画工具安装、使用、技巧等总结《HTML网站开发相关》《前端基础入门三大核心之html相关博客》前端基础入门三大核心之html板块的内容入坑前端或者辅助学习的必看知识《前端基础入门三大核心之JS相关博客》前端JS是JavaScript语言在网页开发中的应用负责实现交互效果和动态内容。它与HTML和CSS并称前端三剑客共同构建用户界面。通过操作DOM元素、响应事件、发起网络请求等JS使页面能够响应用户行为实现数据动态展示和页面流畅跳转是现代Web开发的核心《前端基础入门三大核心之CSS相关博客》介绍前端开发中遇到的CSS疑问和各种奇妙的CSS语法同时收集精美的CSS效果代码用来丰富你的web网页《canvas绘图相关博客》Canvas是HTML5中用于绘制图形的元素通过JavaScript及其提供的绘图API开发者可以在网页上绘制出各种复杂的图形、动画和图像效果。Canvas提供了高度的灵活性和控制力使得前端绘图技术更加丰富和多样化《Vue实战相关博客》持续更新中~详细总结了常用UI库elementUI的使用技巧以及Vue的学习之旅《python相关博客》持续更新中~Python简洁易学的编程语言强大到足以应对各种应用场景是编程新手的理想选择也是专业人士的得力工具《sql数据库相关博客》持续更新中~SQL数据库高效管理数据的利器学会SQL轻松驾驭结构化数据解锁数据分析与挖掘的无限可能《算法系列相关博客》持续更新中~算法与数据结构学习总结通过JS来编写处理复杂有趣的算法问题提升你的技术思维《IT信息技术相关博客》持续更新中~作为信息化人员所需要掌握的底层技术涉及软件开发、网络建设、系统维护等领域的知识《信息化人员基础技能知识相关博客》无论你是开发、产品、实施、经理只要是从事信息化相关行业的人员都应该掌握这些信息化的基础知识可以不精通但是一定要了解避免日常工作中贻笑大方《信息化技能面试宝典相关博客》涉及信息化相关工作基础知识和面试技巧提升自我能力与面试通过率扩展知识面《前端开发习惯与小技巧相关博客》持续更新中~罗列常用的开发工具使用技巧,如 Vscode快捷键操作、Git、CMD、游览器控制台等《photoshop相关博客》持续更新中~基础的PS学习记录含括PPI与DPI、物理像素dp、逻辑像素dip、矢量图和位图以及帧动画等的学习总结日常开发办公生产【实用工具】分享相关博客》持续更新中~分享介绍各种开发中、工作中、个人生产以及学习上的工具丰富阅历给大家提供处理事情的更多角度学习了解更多的便利工具如Fiddler抓包、办公快捷键、虚拟机VMware等工具吾辈才疏学浅摹写之作恐有瑕疵。望诸君海涵赐教。望轻喷嘤嘤嘤非常期待和您一起在这个小小的网络世界里共同探索、学习和成长。愿斯文对汝有所裨益纵其简陋未及渊博亦足以略尽绵薄之力。倘若尚存阙漏敬请不吝斧正俾便精进