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

时间:2016-05-02 20:33:02

标签: javascript ruby-on-rails angularjs amazon-s3 oauth

我的用户拥有需要由经过身份验证的用户下载的私人文件。我的服务器首先使用它自己的S3 app_id / secret_token凭据从S3下载文件。然后构建下载的文件并使用Rails' send_data方法。

Ruby(在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 Unauthorized Error。

相反,我需要使用ng-click触发下载,然后从角度控制器执行$ 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保存文件的简单库(显然在客户端上)。

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

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

提前致谢。

3 个答案:

答案 0 :(得分:1)

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

Rails'send_data文档:

  

将给定的二进制数据发送到浏览器。这种方法类似于   render plain:data,还允许你指定是否浏览器   应将响应显示为文件附件(即在下载中)   对话框)或内联数据。您也可以设置内容类型   表观文件名和其他东西。

Angular的$http文档在$ http的 responseType 配置方面非常差。从本质上讲,需要通过将responseType设置为“arraybuffer”(见下文)来告诉$ http预期二进制数据响应。

$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 documentation可能比以下更具描述性:

  

用法

     

$ HTTP(配置);

     

参数

     

配置

     

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

答案 1 :(得分:0)

您好我有一个示例,说明如何从我的服务器下载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 project

中查看所有代码

答案 2 :(得分:0)

我认为你使用javascript解决方案走在正确的轨道上,但只是有一个错字。在$http.get调用中,您传递一个空对象作为第二个参数。这是{responseType: arraybuffer}的options参数应该已经消失的地方。请在此处查看$http.get的文档: https://docs.angularjs.org/api/ng/service/ $ HTTP GET#