从 WebAPI 获取 PDF 并从 UI 下载,但数据已损坏

Posted

技术标签:

【中文标题】从 WebAPI 获取 PDF 并从 UI 下载,但数据已损坏【英文标题】:Get PDF from WebAPI and download from UI, but data gets corrupted 【发布时间】:2019-08-16 23:19:53 【问题描述】:

我从 UI 调用 Web API 控制器,然后从 s-s-rS 获取报告。它在响应的内容中插入字节并将其发送到 UI,在那里它以 PDF 格式下载。

在我的 Web API 控制器中,我将报告字节写入测试 PDF 文件,以检查 pdf 的内容并查看数据是否正确,即正确。但是,当从我的 UI 下载 PDF 并打开它时,我得到一个空白页文档。当我检查 Fiddler 中的响应内容时,我可以看到数据已损坏并且与测试 PDF 文件数据不匹配。

服务器端:

[HttpPost]
public HttpResponseMessage GetInstancePdf(InstancePdfModel model) 
  var bytes = _digitalFormService.GetInstancePdf(model.ClientGuid, model.InstanceGuid, model.InstanceVersion);

  File.WriteAllBytes(@ "c:\temp\test.pdf", bytes);

  var response = Request.CreateResponse();

  response.Content = new ByteArrayContent(bytes);
  response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue(DispositionTypeNames.Inline) 
    FileName = "file.pdf"
  ;
  response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");

  return response;

客户端:

$scope.downloadPdf = function(instance) 
  $scope.isBusy = true;
  digitalFormService.getInstancePdf(instance.instanceGuid, instance.instanceVersion).then(function(data) 
    if (data.status === 200) 
      const file = new Blob([data.data], 
        type: data.headers("Content-Type")
      );
      if (navigator.appVersion.toString().indexOf(".NET") > 0) 
        window.navigator.msSaveBlob(file, (`$instance.name $(new Date()).toLocaleString()`).replace(",", ""));
       else 
        //trick to download, store a file having its URL
        const fileUrl = URL.createObjectURL(file);
        const a = document.createElement("a");
        a.href = fileUrl;
        a.target = "_blank";
        a.download = (`$instance.name $(new Date()).toLocaleString()`).replace(",", "");
        document.body.appendChild(a);
        a.click();
      
     else 
      debugger;
    
    $scope.isBusy = false;
  );
;

function getInstancePdf(instanceGuid, instanceVersion) 
  var data = 
    clientGuid: digitalFormConfig.clientToken,
    instanceGuid: instanceGuid,
    instanceVersion: instanceVersion
  ;
  return $http(
    url: digitalFormConfig.serverUrl +
      "api/DigitalForm/GetInstancePdf",
    dataType: "json",
    data: data,
    method: "POST"
  ).then(function(response) 
      return response;
    ,
    function() 
      return $q.reject("No Data");
    );

我希望我下载的 PDF 是一个信息文档,与保存在 Web API 控制器中的测试 PDF 文件相匹配,但我得到的是一个空白文档(与测试文件的页数相同,但为空白)。

我使用 Fiddler 检查响应正文。当我将 Fiddler 中的响应正文保存为 pdf 时 - 一切都很好。所以我确信我的服务器端代码是正确的。问题一定出在客户端的某个地方。

有什么帮助吗?谢谢。

【问题讨论】:

不是这方面的权威,但看起来您正在接收二进制数据和 JS 期望字符串作为响应。我想从服务器获取链接并在选项卡中打开它会是一个更好的选择 How to return a file using Web API?的可能重复 我使用 Fiddler 检查响应正文。当我将 Fiddler 中的响应正文保存为 pdf 时 - 一切都很好。所以我确信我的服务器端代码是正确的。问题一定出在客户端的某个地方。 Returning binary file from controller in ASP.NET Web API的可能重复 如果您不发布数据,这项工作会更容易。我真的想不出任何理由 ClientGuid InstanceGuidInstanceVersion 不应该用作查询字符串参数,而不是放在对象中并发布。将文件作为获取请求提供比将其作为对 JQuery json 帖子的响应要容易得多。 【参考方案1】:

我发现了错误。该错误位于客户端服务中。代码应如下所示:

function getInstancePdf(instanceGuid, instanceVersion) 
    var data = 
        clientGuid: digitalFormConfig.clientToken,
        instanceGuid: instanceGuid,
        instanceVersion: instanceVersion
    ;
    return $http(
        responseType: "arraybuffer",
        url: digitalFormConfig.serverUrl +
            "api/DigitalForm/GetInstancePdf",
        dataType: "json",
        data: data,
        method: "POST"
    ).then(function (response) 
            return response;
        ,
        function () 
            return $q.reject("No Data");
        );

responseType: "arraybuffer", 行之前被省略了。

【讨论】:

以上是关于从 WebAPI 获取 PDF 并从 UI 下载,但数据已损坏的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Objective-C 的 NSDocument 目录中保存和获取多个 pdf 文件?

.net webapi后台返回pdf文件流,前端ajax请求下载,空白pdf排错经历

.net webapi后台返回pdf文件流,前端ajax请求下载,空白pdf排错经历

在 post call 中读取一个 json 对象并从所有名称值对中获取值

使用Google应用脚本从PDF到文本转换获取文本

如何获取 OData 可查询 Web API 端点过滤器并从 DTO 对象映射它?