Window.Open 使用 PDF 流而不是 PDF 位置

Posted

技术标签:

【中文标题】Window.Open 使用 PDF 流而不是 PDF 位置【英文标题】:Window.Open with PDF stream instead of PDF location 【发布时间】:2014-05-11 08:57:55 【问题描述】:

基于问题Open PDF in new browser full window,看来我可以使用javascript打开一个带有PDF文件的新窗口,其中包含以下代码:

window.open('MyPDF.pdf', '_blank');

我想在从服务器返回时这样做,方法是添加一个字节数组而不是文件名,用作window.open 中的 URL 位置

我目前正在返回 PDF 文件,例如 this:

Response.Clear();
Response.ContentType = "application/pdf";
Response.BinaryWrite(pdfByteArray);
Response.Flush();

有没有办法在javascript中打开一个带有PDF字节数组的新窗口。

类似这样的:

var script = "window.open('" + pdfByteArray + "', '_blank');";
ScriptManager.RegisterClientScriptBlock(Parent.Page, typeof(Page), "pdf", script, true);

【问题讨论】:

为什么不创建一个处理程序 (.ashx) 来执行输出并使用 window.open 来指向它。您只能将 uri/url 传递给 window.open w3schools.com/jsref/met_win_open.asp 【参考方案1】:

看起来window.open 会将数据 URI 作为位置参数。

所以你可以从问题中这样打开它:Opening PDF String in new window with javascript:

window.open("data:application/pdf;base64, " + base64EncodedPDF);

这是一个 runnable example in plunker 和 sample pdf file,它已经被 base64 编码。

然后在服务器上,你可以像这样将字节数组转换为base64编码:

string fileName = @"C:\TEMP\TEST.pdf";
byte[] pdfByteArray = System.IO.File.ReadAllBytes(fileName);
string base64EncodedPDF = System.Convert.ToBase64String(pdfByteArray);

注意:这似乎很难在 IE 中实现,因为 URL 长度太小,无法发送整个 PDF。

【讨论】:

在阅读了有关类似问题的各种其他 cmets 之后,似乎有些人声称限制在 2048 字节和 32KB 之间。不幸的是,这两个对我来说都太小了。看起来仍然没有可靠的方法来告诉用户他们的 PDF 下载何时完成生成缺少 ajax 轮询线程。 我需要导入哪个库才能使用System.Convert.ToBase64String?我在System pkg 中找不到Convert 我在后端使用 php,所以我在发送 pdf 内容之前制作了 base64_encode(data)(跳过了你在那里写的 System.Convert.ToBase64String;它不适合我)。谢谢! @KyleMit 很棒很棒的解决方案 我需要更进一步,自动触发浏览器的“打印”功能。但是当我从新窗口对象调用window.print() 时,它什么也不做。我什至尝试调用setTimeout 以确保它已加载,但它不起作用。有人有什么想法吗?【参考方案2】:

注意:我已经在最新版本的 IE 以及 Mozilla 和 Chrome 等其他浏览器中验证了这一点,这对我有用。希望它也适用于其他人。

if (data == "" || data == undefined) 
    alert("Falied to open PDF.");
 else  //For IE using atob convert base64 encoded data to byte array
    if (window.navigator && window.navigator.msSaveOrOpenBlob) 
        var byteCharacters = atob(data);
        var byteNumbers = new Array(byteCharacters.length);
        for (var i = 0; i < byteCharacters.length; i++) 
            byteNumbers[i] = byteCharacters.charCodeAt(i);
        
        var byteArray = new Uint8Array(byteNumbers);
        var blob = new Blob([byteArray], 
            type: 'application/pdf'
        );
        window.navigator.msSaveOrOpenBlob(blob, fileName);
     else  // Directly use base 64 encoded data for rest browsers (not IE)
        var base64EncodedPDF = data;
        var dataURI = "data:application/pdf;base64," + base64EncodedPDF;
        window.open(dataURI, '_blank');
    


【讨论】:

我终于得到了使用 .NET 组合的东西: Response.Write(System.Convert.ToBase64String(bytearray));和上面的 javascript 块。谢谢@KyleMit! 在 Chrome 中,我在打开 PDF 时收到 Not allowed to navigate top frame to data URL【参考方案3】:

添加到 @Dinesh 的答案以处理 Chrome 和 Edge 中的 Not allowed to navigate top frame to data URL 错误

if (data == "" || data == undefined) 
    // Log Error: PDF data not available
 else 
    var byteCharacters = atob(data);                        
    var byteNumbers = new Array(byteCharacters.length);
    for (var i = 0; i < byteCharacters.length; i++) 
      byteNumbers[i] = byteCharacters.charCodeAt(i);
    
    var byteArray = new Uint8Array(byteNumbers);
    var file = new Blob([byteArray],  type: 'application/pdf;base64' );
                            
    if (window.navigator && window.navigator.msSaveOrOpenBlob) 
        // For IE
        window.navigator.msSaveOrOpenBlob(file, 'mypdf.pdf');
     else 
        // For non-IE
        var fileURL = URL.createObjectURL(file);
        window.open(fileURL);
    

【讨论】:

以上是关于Window.Open 使用 PDF 流而不是 PDF 位置的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 window.open() 显示窗口标题?

为啥我的数据被解释为可读流而不是 json 对象?

从流而不是文件加载配置文件

如何将身份验证标头添加到 $window.open

您可以使用流而不是本地文件上传到 S3 吗?

在 svm-predict 命令中使用字符串流而不是文件流