ASP.NET Web Forms中Chrome65/Firefox58下Crystal Report打印空白页及JS问题
解决ASP.NET Web Forms中Crystal Report在Chrome 65+/Firefox 58+打印空白页的问题
我之前碰到过好几个开发者在升级浏览器后遇到这个Crystal Report打印空白的问题,主要是现代浏览器对iframe内容的加载时机、跨上下文访问的限制变严格了,加上内置PDF查看器的行为和旧版插件不一样。咱们一步步来排查解决:
可能的问题根源
- iframe内容未完全加载就触发打印:原代码里没有等待iframe里的PDF完全渲染完成就调用
print(),新浏览器的异步加载机制会导致打印时内容还没准备好。 - 跨上下文访问限制:Chrome 65+和Firefox 58+加强了对iframe窗口对象的访问控制,原代码里直接访问
window.frames[frame1.id]的方式可能因为安全策略被阻止。 - 内置PDF查看器的兼容性:新浏览器默认用内置PDF查看器替代了Adobe Reader插件,这些内置工具对
print()方法的触发时机要求更严格。
具体解决方案
方案1:等待iframe完全加载后再打印(修改原有JS代码)
最直接的调整是给iframe加上加载完成的监听,确保PDF渲染好再执行打印,同时适配现代浏览器的窗口对象获取方式:
function onPrintPickRPT() { var dvReport = document.getElementById("dvReport"); var frame1 = dvReport.getElementsByTagName("iframe")[0]; // 确保iframe加载完成后再打印 frame1.onload = function() { if (navigator.appName.indexOf("Internet Explorer") !== -1) { frame1.name = frame1.id; window.frames[frame1.id].focus(); window.frames[frame1.id].print(); } else { // 现代浏览器正确获取iframe的window对象 var frameWindow = frame1.contentWindow || frame1.contentDocument.defaultView; frameWindow.focus(); // 加个小延迟确保PDF内容完全渲染 setTimeout(function() { frameWindow.print(); }, 500); } }; // 重新触发iframe加载(避免缓存导致的加载事件不触发) frame1.src = frame1.src; }
方案2:直接打印PDF数据流(更稳定的现代方案)
如果iframe方式还是有兼容性问题,建议直接从后台获取PDF的二进制流,通过Blob对象在新窗口打开后打印,这种方式不受iframe的安全限制:
function onPrintPickRPT() { // 替换成你生成Crystal Report PDF的后台接口 fetch('/PickReport.aspx/GetPrintablePDF', { method: 'POST', headers: { 'Content-Type': 'application/json' }, // 如果需要传递报表参数,这里序列化后传入 body: JSON.stringify({ reportId: '123', userId: '456' }) }) .then(response => response.blob()) .then(blob => { const pdfUrl = URL.createObjectURL(blob); const printWindow = window.open(pdfUrl, '_blank'); printWindow.onload = function() { printWindow.print(); // 打印完成后释放URL资源并关闭窗口 setTimeout(() => { URL.revokeObjectURL(pdfUrl); printWindow.close(); }, 1000); }; }) .catch(err => console.error('生成PDF失败:', err)); }
然后在你的ASP.NET Web Forms页面里添加对应的WebMethod来生成PDF:
using CrystalDecisions.CrystalReports.Engine; using System.IO; using System.Web.Services; public partial class PickReport : System.Web.UI.Page { [WebMethod] public static byte[] GetPrintablePDF(string reportId, string userId) { // 初始化Crystal Report var report = new ReportDocument(); report.Load(Server.MapPath("~/Reports/PickList.rpt")); // 设置报表参数 report.SetParameterValue("ReportId", reportId); report.SetParameterValue("UserId", userId); // 导出为PDF字节流 using (var ms = new MemoryStream()) { report.ExportToStream(ExportFormatType.PortableDocFormat).CopyTo(ms); return ms.ToArray(); } } }
方案3:临时调整浏览器设置(仅测试环境用)
如果是紧急测试可以试试,但不推荐生产环境使用,因为现代浏览器正在逐步淘汰NPAPI插件:
- Chrome:在地址栏输入
chrome://flags/#enable-npapi,启用NPAPI选项后重启浏览器(注意部分高版本Chrome已经移除了这个选项) - Firefox:在地址栏输入
about:config,搜索plugin.scan.plid.all设为true,plugin.scan.Acrobat设为99.9999,然后安装Adobe Reader插件替代内置PDF查看器
总结
优先用方案1或方案2,方案3只是临时的过渡方案,因为浏览器厂商都在推进无插件的Web体验,方案2的Blob打印方式更符合现代Web标准,兼容性也更好。
内容的提问来源于stack exchange,提问作者kvitas
相关产品推荐
相关产品推荐

