javascript - 使用 $http.get() 通过 Angular 下载远程文件 - OAuth 身份验证

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

我的用户有私有(private)文件需要由经过身份验证的用户下载。我的服务器首先使用它自己的 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 拦截器无法捕获这种类型的外部链接点击,因此不会为服务器端身份验证附加适当的 header 。结果是 401 未经授权的错误。

相反,我需要使用 ng-click 触发下载,然后从 Angular Controller 执行 $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文档:

Sends the given binary data to the browser. This method is similar to render plain: data, but also allows you to specify whether the browser should display the response as a file attachment (i.e. in a download dialog) or as inline data. You may also set the content type, the apparent file name, and other things.

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

Usage

$http(config);

Arguments

config

responseType - {string} - see XMLHttpRequest.responseType.

关于javascript - 使用 $http.get() 通过 Angular 下载远程文件 - OAuth 身份验证,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36991167/

相关文章:

javascript - 在 Cypress 中测试图像加载

javascript - 如何在文本框中获取上一个和下一个日期

javascript - 如何从由 image_tag 等 Rails 助手生成的 HTML 中选择 DOM 元素?

ruby-on-rails - 将一个或两个参数传递给Rake任务

ruby-on-rails - 如何让 Sidekiq 在 Heroku 上工作?

angularjs - 如何使用 AngularJS 构建 CodeIgniter 应用程序?

javascript - 带有 '?x=y' 查询的 jQuery BBQ 推送状态

javascript - 使用 html5 canvas 的 JavaScript 中的鼠标单击事件

javascript - 为什么我无法获得对 AngularJS Videogular 中可以看到的元素的引用?

angularjs - 从指令链接调用 $http.get