如何在AngularJS应用程序中显示blob(.pdf)

114

我一直在尝试显示PDF文件,该文件作为从$http.post响应中获取。例如,必须使用<embed src>在应用程序内部显示PDF。

我看了几篇这方面的技术文章,但是我的示例似乎无法正常工作。

JS:

根据这份文档,我进行了尝试...

$http.post('/postUrlHere',{myParams}).success(function (response) {
 var file = new Blob([response], {type: 'application/pdf'});
 var fileURL = URL.createObjectURL(file);
 $scope.content = fileURL;
});

现在据我所知,fileURL会创建一个临时 URL,供博客参考。

HTML:

<embed src="{{content}}" width="200" height="200"></embed>

我不确定如何在 Angular 中处理这个问题,理想情况是要(1)将它分配到作用域中,(2)将blob准备/重建为PDF,(3)使用 <embed> 将其传递给HTML,因为我想在应用程序内显示它。

我已经研究了一天多了,但不知何故似乎无法理解它在Angular中的工作方式...假设现有的pdf查看器库不是一个选项。


嗨,D'lo DeProjuicer,你是否解决了使用Angular生成PDF的问题? - Raymond Nakampe
@michael D'lo DeProjuicer,在Angular 2中应该怎么做才能处理同样的情况? - monica
8个回答

222

首先,您需要将responseType设置为arraybuffer。如果您想创建数据的blob,则需要这样做。请参见Sending_and_Receiving_Binary_Data。因此,您的代码将如下所示:

$http.post('/postUrlHere',{myParams}, {responseType:'arraybuffer'})
  .success(function (response) {
       var file = new Blob([response], {type: 'application/pdf'});
       var fileURL = URL.createObjectURL(file);
});

接下来,您需要使用$sce服务来使 Angular 信任您的 URL。您可以按照以下方式完成:

$scope.content = $sce.trustAsResourceUrl(fileURL);

不要忘记注入$sce服务。

如果这些都做好了,现在您可以嵌入您的pdf文件:

<embed ng-src="{{content}}" style="width:200px;height:200px;"></embed>

9
在Chrome浏览器(35.0.1916.114 m)中,对我来说这并没有起作用。通过使用<object>代替<embed>解决了这个问题:<object data="{{content}}" type="application/pdf"></object>。 - HoffZ
2
对于我来说(AngularJS 1.25),我需要执行以下操作:new Blob([response.data] - Martin Connell
2
@HoffZ:我用完整的方法替换了快捷方式$http.get,并指定了responseType字段:{ url: "http://127.0.0.1:8080/resources/jobs/af471106-2e71-4fe6-946c-cd1809c659e5/result/?key="+$scope.key, method: "GET", headers: { 'Accept': 'application/pdf' }, responseType: 'arraybuffer' } 现在它可以正常工作 :) - Nikolay Melnikov
1
对我来说,使其工作的唯一方法是使用response.data而不是response创建blob,像这样:var file = new Blob([response.data], {type: 'application/pdf'}); - Alekos Filini
1
@yosep-kim,这在IE上不起作用,因为URL对象在IE中不存在:http://caniuse.com/#search=URL - Carlos
显示剩余7条评论

34

我使用的是AngularJS v1.3.4

HTML:

<button ng-click="downloadPdf()" class="btn btn-primary">download PDF</button>

JS 控制器:

'use strict';
angular.module('xxxxxxxxApp')
    .controller('xxxxController', function ($scope, xxxxServicePDF) {
        $scope.downloadPdf = function () {
            var fileName = "test.pdf";
            var a = document.createElement("a");
            document.body.appendChild(a);
            a.style = "display: none";
            xxxxServicePDF.downloadPdf().then(function (result) {
                var file = new Blob([result.data], {type: 'application/pdf'});
                var fileURL = window.URL.createObjectURL(file);
                a.href = fileURL;
                a.download = fileName;
                a.click();
            });
        };
});

JS服务:

angular.module('xxxxxxxxApp')
    .factory('xxxxServicePDF', function ($http) {
        return {
            downloadPdf: function () {
            return $http.get('api/downloadPDF', { responseType: 'arraybuffer' }).then(function (response) {
                return response;
            });
        }
    };
});

Java REST Web服务 - Spring MVC:

@RequestMapping(value = "/downloadPDF", method = RequestMethod.GET, produces = "application/pdf")
    public ResponseEntity<byte[]> getPDF() {
        FileInputStream fileStream;
        try {
            fileStream = new FileInputStream(new File("C:\\xxxxx\\xxxxxx\\test.pdf"));
            byte[] contents = IOUtils.toByteArray(fileStream);
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.parseMediaType("application/pdf"));
            String filename = "test.pdf";
            headers.setContentDispositionFormData(filename, filename);
            ResponseEntity<byte[]> response = new ResponseEntity<byte[]>(contents, headers, HttpStatus.OK);
            return response;
        } catch (FileNotFoundException e) {
           System.err.println(e);
        } catch (IOException e) {
            System.err.println(e);
        }
        return null;
    }

哪个版本的Safari?window.URL在Safari 9及以上版本中表现良好:http://caniuse.com/#search=createObjectURL - Stéphane GRILLON
我在我的MacBook Pro和Safari 9.0.2上进行了测试和验证。 - Stéphane GRILLON
一样的,macBook el captain。window.URL.createObjectURL(file); 我不知道问题出在哪里,但代码不起作用。可能是我做错了什么。谢谢。我没有时间检查它为什么不工作并使用FileSaver.js。 - fdrv
在api/downloadPDF中->它只包含字节数组。如果是字节数组,对我来说无法工作。如果我提供本地文件x.pdf,则我的pdf会呈现在页面上。我不想下载。 我需要使用angular在页面本身中显示pdf文件。 您能否提供显示视图中pdf文件的解决方案? - Raphael
如果在头文件中放置“application/pdf”,则您的PDF将在选项卡浏览器中打开。在Java中 => headers.setContentType(MediaType.parseMediaType(“application / pdf”)); - Stéphane GRILLON
显示剩余4条评论

23

michael的建议对我非常有效 :) 如果你用$http.get代替$http.post,请记住,.get方法只接受两个参数而不是三个...这就是我浪费时间的地方... ;)

控制器:

$http.get('/getdoc/' + $stateParams.id,     
{responseType:'arraybuffer'})
  .success(function (response) {
     var file = new Blob([(response)], {type: 'application/pdf'});
     var fileURL = URL.createObjectURL(file);
     $scope.content = $sce.trustAsResourceUrl(fileURL);
});

查看:

<object ng-show="content" data="{{content}}" type="application/pdf" style="width: 100%; height: 400px;"></object>

1
responseType:'arraybuffer',这刚刚为我省下了几个睡眠时间!+1 - svarog
如何触发保存而不是将其打印在HTML中? - fdrv
谢谢,这节省了我好几个小时。你还可以将“$scope.content = $sce.trustAsResourceUrl(fileURL);”替换为“$window.open(fileURL, '_self', '');”,并在全屏模式下打开文件。 - Tavitos

10

在使用Opera浏览器时,我遇到了使用"window.URL"的困难,因为它会导致结果为"undefined"。此外,使用window.URL时,在Internet Explorer和Microsoft Edge中PDF文档永远不会打开(它将永远等待)。我想出了以下解决方案,可以在IE,Edge,Firefox,Chrome和Opera中使用(尚未在Safari中进行测试):

$http.post(postUrl, data, {responseType: 'arraybuffer'})
.success(success).error(failed);

function success(data) {
   openPDF(data.data, "myPDFdoc.pdf");
};

function failed(error) {...};

function openPDF(resData, fileName) {
    var ieEDGE = navigator.userAgent.match(/Edge/g);
    var ie = navigator.userAgent.match(/.NET/g); // IE 11+
    var oldIE = navigator.userAgent.match(/MSIE/g); 

    var blob = new window.Blob([resData], { type: 'application/pdf' });

    if (ie || oldIE || ieEDGE) {
       window.navigator.msSaveBlob(blob, fileName);
    }
    else {
       var reader = new window.FileReader();
       reader.onloadend = function () {
          window.location.href = reader.result;
       };
       reader.readAsDataURL(blob);
    }
}

如果有帮助,请告诉我!:)


这种方法不会在IE浏览器窗口中打开PDF文档,而是提示用户下载。有没有什么解决办法? - sdd
1
以上代码是用于下载PDF文件并让默认的PDF阅读器应用程序接管打开它。它甚至在移动设备上运行良好。原因是,虽然我能够在某些浏览器上打开PDF,但在其他浏览器上无法打开。因此,我认为最好有一个解决方案,可以在所有浏览器(包括移动浏览器)上运行以下载PDF文件。 - Manuel Hernandez
您可以使用以下代码在新标签页中查看PDF:window.open(reader.result, '_blank'); - samneric

6

在从Angular发出的请求中添加responseType确实是解决方案,但直到我将responseType设置为blob而不是arrayBuffer时才起作用。代码本身很清楚:

    $http({
            method : 'GET',
            url : 'api/paperAttachments/download/' + id,
            responseType: "blob"
        }).then(function successCallback(response) {
            console.log(response);
             var blob = new Blob([response.data]);
             FileSaver.saveAs(blob, getFileNameFromHttpResponse(response));
        }, function errorCallback(response) {   
        });

2
实际上,使用“blob”类型可以更短地写出以下代码: FileSaver.saveAs(response.data, getFileNameFromHttpResponse(response)); 无需创建“Blob”。 - Alena Kastsiukavets

1

最近的答案(适用于Angular 8+):

this.http.post("your-url",params,{responseType:'arraybuffer' as 'json'}).subscribe(
  (res) => {
    this.showpdf(res);
  }
)};

public Content:SafeResourceUrl;
showpdf(response:ArrayBuffer) {
  var file = new Blob([response], {type: 'application/pdf'});
  var fileURL = URL.createObjectURL(file);
  this.Content = this.sanitizer.bypassSecurityTrustResourceUrl(fileURL);
}

  HTML :

  <embed [src]="Content" style="width:200px;height:200px;" type="application/pdf" />

0

我过去几天一直在努力下载PDF和图像,但我只能下载简单的文本文件。

大多数问题都有相同的组件,但是花了一段时间才找出正确的顺序使其正常工作。

谢谢@Nikolay Melnikov,您对这个问题的评论/回复使它正常工作。

简而言之,这是我的AngularJS服务后端调用:

  getDownloadUrl(fileID){
    //
    //Get the download url of the file
    let fullPath = this.paths.downloadServerURL + fileId;
    //
    // return the file as arraybuffer 
    return this.$http.get(fullPath, {
      headers: {
        'Authorization': 'Bearer ' + this.sessionService.getToken()
      },
      responseType: 'arraybuffer'
    });
  }

从我的控制器:

downloadFile(){
   myService.getDownloadUrl(idOfTheFile).then( (response) => {
      //Create a new blob object
      let myBlobObject=new Blob([response.data],{ type:'application/pdf'});

      //Ideally the mime type can change based on the file extension
      //let myBlobObject=new Blob([response.data],{ type: mimeType});

      var url = window.URL || window.webkitURL
      var fileURL = url.createObjectURL(myBlobObject);
      var downloadLink = angular.element('<a></a>');
      downloadLink.attr('href',fileURL);
      downloadLink.attr('download',this.myFilesObj[documentId].name);
      downloadLink.attr('target','_self');
      downloadLink[0].click();//call click function
      url.revokeObjectURL(fileURL);//revoke the object from URL
    });
}

-2

这是我在使用AngularJS v1.7.2开发项目时刚刚用过的一段代码建议。

$http.get('LabelsPDF?ids=' + ids, { responseType: 'arraybuffer' })
            .then(function (response) {
                var file = new Blob([response.data], { type: 'application/pdf' });
                var fileURL = URL.createObjectURL(file);
                $scope.ContentPDF = $sce.trustAsResourceUrl(fileURL);
            });

<embed ng-src="{{ContentPDF}}" type="application/pdf" class="col-xs-12" style="height:100px; text-align:center;" />

1
please add some brief too. - Farhana Naaz Ansari

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接