javascript - 动态 PDF 并打开新窗口而不是下载

标签 javascript ajax pdf blob

我有一个 Web api,它将 JSReport 作为编码字节数组返回。无论我如何尝试读取字节数组,我要么得到黑屏,要么得到一条错误消息,提示“无法下载 pdf”。如果我创建一个隐藏的 anchor 标记并下载 pdf,它就可以正常工作。但是,我不希望用户下载它,我希望他们可以直接从浏览器查看它。

WEB API 调用

   var data = LossReportService.GetLossSummary(request);
   var pdf_bytes = LossReportService.GeneratePDFUsingJSReport(data);

   byte[] myBinary = new byte[pdf_bytes.Length];
   pdf_bytes.Read(myBinary, 0, (int)pdf_bytes.Length);
   string base64EncodedPDF = System.Convert.ToBase64String(myBinary);

   var response = Request.CreateResponse(HttpStatusCode.OK, base64EncodedPDF);
   response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
   response.Content.Headers.ContentLength = pdf_bytes.Length;

   return response;                  

Javascript

$.ajax({
    type: "POST",
    url: "/Reporting/GetLossSummary",
    data: { dataObj },
},
success: function (data) {
   if (data != null) {

    //I have tried this
    var file = new Blob([data], { type: 'application/pdf;base64' });
    var fileURL = URL.createObjectURL(file);
    window.open(fileURL, "LossSummaryReport");

    //which gives me a "failed to load pdf document" error

    //and I have tried this, which just renders a blank page
    window.open("data:application/pdf," + encodeURI(data)); 
  }
}
});

如有任何建议,我们将不胜感激。

最佳答案

由于您使用的是jsreport,一般情况下,您可以使用jsreport browser sdk更好地处理报告结果并轻松在浏览器中显示它。但就您而言,您在服务器中使用自定义 url 来呈现报告,因此 jsreport 浏览器 sdk 在这种情况下无法帮助您。您需要使用 jQuery ajax 或纯 XMLHttpRequest 来处理报告请求和响应。

使用 jQuery.ajax 很难处理 blob/二进制数据,您需要 add a data transport to $.ajax in order to handle binary data

/**
 *
 * jquery.binarytransport.js
 *
 * @description. jQuery ajax transport for making binary data type requests.
 * @version 1.0 
 * @author Henry Algus <henryalgus@gmail.com>
 *
 */

// use this transport for "binary" data type
$.ajaxTransport("+binary", function(options, originalOptions, jqXHR){
    // check for conditions and support for blob / arraybuffer response type
    if (window.FormData && ((options.dataType && (options.dataType == 'binary')) || (options.data && ((window.ArrayBuffer && options.data instanceof ArrayBuffer) || (window.Blob && options.data instanceof Blob)))))
    {
        return {
            // create new XMLHttpRequest
            send: function(headers, callback){
        // setup all variables
                var xhr = new XMLHttpRequest(),
        url = options.url,
        type = options.type,
        async = options.async || true,
        // blob or arraybuffer. Default is blob
        dataType = options.responseType || "blob",
        data = options.data || null,
        username = options.username || null,
        password = options.password || null;

                xhr.addEventListener('load', function(){
            var data = {};
            data[options.dataType] = xhr.response;
            // make callback and send data
            callback(xhr.status, xhr.statusText, data, xhr.getAllResponseHeaders());
                });

                xhr.open(type, url, async, username, password);

        // setup custom headers
        for (var i in headers ) {
            xhr.setRequestHeader(i, headers[i] );
        }

                xhr.responseType = dataType;
                xhr.send(data);
            },
            abort: function(){
                jqXHR.abort();
            }
        };
    }
});

但是在处理请求/响应中的 blob 数据时,我更喜欢直接使用 XHTMLRequest 进行处理,因为它可以让我以任何我想要的方式操纵响应。

function sendReportRequest (dataObj, cb) {
  var xhr = new XMLHttpRequest()
  var data = JSON.stringify(dataObj)

  xhr.open('POST', 'http://url-of-your-server/' + '/Reporting/GetLossSummary', true)
  xhr.setRequestHeader('Content-type', 'application/json; charset=utf-8')
  xhr.responseType = 'arraybuffer'

  xhr.onload = function () {
    if (this.status >= 200 && this.status < 300) {
      var response = xhr.response
      var contentType = xhr.getResponseHeader('Content-Type')
      var dataView = new DataView(response)
      var blob

      try {
        blob = new Blob([dataView], { type: contentType })
        cb(null, blob)
      } catch (e) {
        if (e.name === 'InvalidStateError') {
          var byteArray = new Uint8Array(response)
          blob = new Blob([byteArray.buffer], { type: contentType })
          cb(null, blob)
        } else {
          cb(new Error('Can not parse buffer response'))
        }
      }
    } else {
      var error = new Error('request failed')

      error.status = xhr.status
      error.statusText = xhr.statusText

      cb(error)
    }
  }

  xhr.onerror = function () {
    var error = new Error('request failed')

    error.status = xhr.status
    error.statusText = xhr.statusText

    cb(error)
  }

  xhr.send(data)
}

sendReportRequest(dataObj, function (err, reportBlob) {
  if (err) {
    return console.error(err)
  }

  var reportFileUrl = URL.createObjectURL(reportBlob)

  window.open(reportFileUrl)
})

使用这段代码,您应该能够请求 pdf 文件并在浏览器的新窗口中显示它

关于javascript - 动态 PDF 并打开新窗口而不是下载,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47893667/

相关文章:

javascript - 如何让 jQuery.ajax 在单个子句中同时涵盖 error() 和complete()?

javascript - 使用javascript在textarea中显示文本

python - 如何使用 R 或 Python 通过 Google Scholar 查询下载学术论文的 PDF

c# - error 该进程无法访问该文件,因为它正被另一个进程使用

python - 如何在 AJAX 请求成功响应中返回文件时打开 PDF 文件

javascript - 如何在未选中单选按钮时隐藏内容并允许查看其他内容

javascript - MongoDB 聚合 () - 错误 "TypeError: Cannot call method ' forEach' of undefined"

javascript - 隐藏的 div 中的元素 ID 是否可用?

javascript - 没有任何 Ajaxed 内容的 Chrome 后退按钮 : only giving cached version of initial page,

javascript - 如何从 tslint 中排除文件夹?