使用$http.get()-OAuth身份验证下载带有Angular的远程文件

Download Remote File With Angular Using $http.get() - OAuth Authentication

本文关键字:Angular 文件 程文件 下载 http get -OAuth 使用 身份验证      更新时间:2023-09-26

我的用户有私人文件,需要由经过身份验证的用户下载。我的服务器首先使用自己的S3 app_id/secret_token凭据从S3下载一个文件。然后,使用Rails的send_data方法构建下载的文件并将其发送到客户端。

Ruby(on Rails):

# documents_controller.rb
def download
  some_file = SomeFile.find(params[:id])
  # download file from AWS S3 to server
  data = open(some_file.document.url) 
  # construct and send downloaded file to client
  send_data data.read, filename: some_file.document_identifier, disposition: 'inline', stream: 'true'
end

最初,我想直接从HTML模板触发下载。

HTML:

<!-- download-template.html -->
<a target="_self" ng-href="{{ document.download_url }}" download="{{document.file_name}}">Download</a>

看起来很简单,但问题是Angular的$http拦截器没有捕捉到这种类型的外部链接点击,因此没有为服务器端身份验证附加适当的标头。结果是401未经授权的错误。

相反,我需要使用ng点击触发下载,然后从角度控制器执行$http.get()请求。

HTML:

<!-- download-template.html -->
<div ng-controller="DocumentCtrl">
  <a ng-click="download(document)">Download</a>
</div>

Javascript:

// DocumentCtrl.js
module.controller( "DocumentCtrl",
  [ "$http", "$scope", "FileSaver", "Blob",
  function( $http, $scope, FileSaver, Blob ) {
    $scope.download = function( document ) {
      $http.get(document.download_url, {}, { responseType: "arraybuffer" } )
        .success( function( data ) {
          var blob = new Blob([data], { type: "application/vnd.openxmlformats-officedocument.wordprocessingml.document" });
          FileSaver.saveAs(blob, document.file_name);
        });
    };
}]);

FileSaver是一个使用Blob(显然是在客户端)保存文件的简单库。

这使我通过了身份验证问题,但导致文件以不可读/不可用的格式保存/下载到客户端。

为什么下载的文件格式不可用

提前谢谢。

Angular的$http方法需要配置为接受二进制数据响应。

Rails的send_data文档:

将给定的二进制数据发送到浏览器。此方法类似于渲染纯文本:数据,但也允许您指定浏览器应将响应显示为文件附件(即在下载中对话框)或作为内联数据。您也可以设置内容类型明显的文件名等。

Angular的$http文档在$http的responseType配置方面非常糟糕。从本质上讲,$http需要通过将responseType设置为"arraybuffer"(见下文)来获得二进制数据响应。

$scope.download = function( document ) {
  console.log("download: ", document);
  $http({
    url: document.download_url,
    method: "GET",
    headers: {
      "Content-type": "application/json"
    },
    responseType: "arraybuffer" // expect to handle binary data response
  }).success( function( data, status, headers ) {
      var type = headers('Content-Type');
      var blob = new Blob([data], { type: type });
      FileSaver.saveAs(blob, document.file_name);
    });
};

Angular的$http文档可能比更具描述性

使用

$http(配置);

参数

配置

responseType-{string}-请参阅XMLHttpRequest.responseType.

嗨,我有一个如何使用angular从服务器下载文件的示例:

我调用带有GET请求的文件:

文件下载html(客户端):

<a ng-href="/api/downloadFile/{{download.id}}" type="submit" class="btn btn-primary col-lg-12 btn-modal-costume" >download</a>

文件下载java(服务器端):

public static Result download(String id) {
        String content = null;
        for (controllers.file file : files) {
            if (file.getId().equals(id)){
                content = file.getContent();
            }
        }
        return ok(new java.io.File("/temp/" + id+ "file" + content)).as("application/force-download");
    }

如果你喜欢,你可以在我的github项目

中查看所有代码

我认为您使用javascript解决方案是正确的,但只是有一个拼写错误。在$http.get调用中,您传递一个空对象作为第二个参数。这就是带有{responseType: arraybuffer}的options参数应该去的地方。请参阅此处的$http.get文档:https://docs.angularjs.org/api/ng/service/$http#get