Chrome跨域帧访问DOMException问题求助(同域不同端口)
问题背景
主域名https://posterprintshop.com调用同域但端口为8443的Web Viewer组件,用于用户下单打印前预览上传文件。偶发DOMException: Blocked a frame with origin 'https://posterprintshop.com' from accessing a cross-origin frame.错误,仅出现在约30%的Windows Chrome用户中。已实现window.postMessage通信但问题仍存在,导致用户误以为文件上传失败流失。
触发路径:用户在/order-wizard页面上传文件成功后跳转至/webv/页面,PDFTron WebViewer在viewer div中注入webviewer-1 iframe时触发报错。
核心错误根源
Chrome同源策略严格校验协议+域名+端口三者完全一致。Web Viewer服务运行在8443端口,主站使用HTTPS默认的443端口,二者属于不同源,直接操作iframe内容会触发跨域拦截。偶发现象源于iframe加载时机、浏览器缓存或安全策略缓存的不一致触发。
遗漏的解决要点
直接跨源操作iframe DOM
WebViewer初始化的then回调中,直接访问instance.iframeWindow.document:const iframeDoc = instance.iframeWindow.document;这行代码直接跨端口操作iframe的document对象,是触发跨域错误的直接原因,必须删除。跨源场景下仅能通过
postMessage通信,禁止直接操作iframe的DOM或window属性。重复绑定事件监听
代码中重复添加window.addEventListener('message', ...),会导致同一事件被多次处理,引发状态混乱。需合并监听逻辑,避免重复绑定。postMessage目标源不精确
当前postMessage的目标源是https://posterprintshop.com,但Web Viewer实际运行在8443端口,正确目标源应为https://posterprintshop.com:8443,否则消息可能被浏览器拦截(偶发错误的诱因之一)。iframe未加载完成时发送消息
WebViewer的then回调触发时,iframe可能未完全加载完成,此时发送postMessage可能无法被接收,甚至触发跨域异常。需等待iframeload事件或WebViewer提供的documentLoaded事件后再发送消息。origin校验不严谨
/webv/页面监听中使用origin.startsWith('https://posterprintshop.com'),存在安全风险(可能匹配到恶意域名如https://posterprintshop.com.evil.com),应精确校验包含端口的完整源:if (event.origin === 'https://posterprintshop.com:8443') { // 处理消息 }未清理事件监听
页面跳转或组件销毁时未移除message事件监听,易引发内存泄漏和后续页面异常。需在页面卸载时调用window.removeEventListener清理监听。
修复后的关键代码示例
WebViewer初始化修正
WebViewer( { path: '<?php echo get_stylesheet_directory_uri() .'/' ?>WebViewer/lib', licenseKey: '<License Key>', initialDoc: '<?php echo get_stylesheet_directory_uri() .'/' ?>pdftest.pdf', documentType: 'pdf', useDownloader: false, mobileRedirect: false, css: '<?php echo get_stylesheet_directory_uri() .'/' ?>css/webviewer.css', }, viewerElement ) .then( async ( instance ) => { console.log( '==> [pdf.php] Instance object ', instance ); // 等待文档加载完成后发送消息 instance.documentViewer.addEventListener('documentLoaded', () => { const iframe = instance.iframeWindow; // 精确指定目标源(包含8443端口) iframe.postMessage( 'iframeTriggerJS', 'https://posterprintshop.com:8443' ); }); // 绑定单一事件监听 const messageHandler = function( event ) { console.log( '==> [pdf.php] Event object ', event ); // 精确校验源 if ( event.origin === 'https://posterprintshop.com:8443' ) { console.log( '==> [pdf.php] Listening...' ); console.log( '==> [pdf.php] Event Data object ', event.data ); } }; window.addEventListener( 'message', messageHandler ); // 页面卸载时清理监听 window.addEventListener('beforeunload', () => { window.removeEventListener('message', messageHandler); }); } );
/webv/页面监听修正
<script> $ = jQuery.noConflict(); $( function( $ ) { const messageHandler = function( event ) { console.log( '==> [pdf.php] Listener triggering from WEBV' ); console.log( '==> [pdf.php] Event object ', event ); // 精确校验源 if ( event.origin === 'https://posterprintshop.com:8443' ) { console.log( '==> [pdf.php] Listening...' ); console.log( '==> [pdf.php] Event Data object ', event.data ); } }; window.addEventListener( 'message', messageHandler ); // 页面卸载时清理监听 window.addEventListener('beforeunload', () => { window.removeEventListener('message', messageHandler); }); } ); </script>
内容的提问来源于stack exchange,提问作者Brett Henrichsen

