1. 为什么 PDF 打印会报跨域错误?
在 Web 应用中嵌入 PDF 文件时,用户点击打印按钮常遇到浏览器控制台抛出'跨域错误'(Cross-Origin Error),导致打印功能失效。这并非小众问题,而是前端开发在处理外部资源时的经典难题。
该错误的根源在于浏览器的同源策略。浏览器为了安全,严格限制了来自不同'源'(协议、域名、端口号任意一个不同)的脚本之间的交互。如果网页部署在 https://your-app.com,而 PDF 文件存放在另一域名下,如 https://cdn.other-domain.com/your-file.pdf,尝试通过 iframe 的 contentWindow.print() 方法调用打印时,浏览器会阻止不安全的跨域访问。错误信息通常显示:Uncaught DOMException: Failed to read a named property 'print' from 'Window': Blocked a frame with origin...。对于只读第三方资源或静态文件托管在 CDN 的场景,修改服务器 CORS 头往往行不通。
本文介绍一种纯前端的解决方案,无需后端配合或服务器配置,完全在浏览器端完成。核心思路是:将跨域的 PDF 文件,'变成'网页自己'本地'的文件,绕过浏览器的同源检查。这一转换依赖于 JavaScript 中的两个关键角色:Blob 对象和动态创建的 iframe。
2. 核心武器拆解:Blob 对象与本地 URL
2.1 Blob 对象:二进制数据容器
Blob(Binary Large Object)是专门用来处理二进制大对象数据的容器。无论是图片、PDF 还是视频,只要拿到二进制流,就能塞进 Blob 对象。
在打印场景中,关键一步是通过 fetch 请求跨域的 PDF 文件。只要服务器未通过 CORS 头禁止,浏览器允许获取响应体。跨域限制真正发威是在试图操作来自不同源的 iframe 内部窗口时。因此,可以安全使用 fetch 并指定 response.blob() 方法,将网络请求回来的 PDF 数据原封不动包装成 Blob 对象。此时,Blob 对象已与最初来源脱钩,成为当前页面上下文'自产'的数据块。
2.2 URL.createObjectURL:生成本地资源地址
光有内存里的数据不够,iframe 的 src 属性认的是 URL 地址。URL.createObjectURL() 接收 Blob 对象作为参数,瞬间生成以 blob: 开头的本地 URL,例如:blob:https://your-app.com/550e8400-e29b-41d4-a716-446655440000。
这个 URL 指向浏览器内存中那个 Blob 对象所代表的数据,且其'源'被浏览器识别为当前网页的源。也就是说,通过这个 blob: URL,我们凭空创建了一个属于当前域的本地资源地址,从而让 iframe 能够合法访问该 PDF 内容并触发打印。

