2016-05-02 20 views
0

我的用戶擁有需要經過身份驗證的用戶下載的私有文件。我的服務器首先使用它自己的S3 app_id/secret_token憑證從S3下載文件。然後構建下載的文件並使用Rails的send_data方法發送給客戶端。

紅寶石(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> 

看起來很簡單,但問題是,角的$ HTTP攔截不抓住這個類型的外部鏈接的點擊,因此相應的頭不追加用於服務器端認證。結果是401未授權錯誤。

相反,我需要使用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是一個簡單的庫保存使用的斑點(在客戶端上,很明顯)文件。

這讓我通過我的身份驗證問題,但導致文件以不可讀/無法格式保存/下載到客戶端。

爲什麼文件以不可用格式下載?

在此先感謝。

+0

您是否必須使用FileSaver?你嘗試過'window.navigator.msSaveOrOpenBlob'和'window.open(objectUrl)'嗎? – Kyle

+0

我不需要使用FileSaver,但使用window.navigator.msSaveOrOpenBlob和window.open(objectUrl)都會導致相同的問題:不可讀的文件格式。它仍然是包裝/構造的文件被Blob重新包裝/構造的情況。 – mikeborgh

回答

0

您好我有我如何從我的服務器下載文件與角的例子:

我打電話跟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

+0

嗨阿里爾,感謝您的迴應,但download仍然繞過Angular的$ http攔截器,因此跳過驗證。我在我的代碼中使用了 – mikeborgh

+0

,我使用了restAngular,但是在文件下載的情況下,我不得不以這種方式使用它,因爲如果不是,它會將該文件作爲後臺請求返回,並且不會將其下載。或者只需要爲GET請求和下載移動到新的URL。 –

0

Angular的$ http方法需要配置爲接受二進制數據響應。

Rails的send_data文檔:

發送給定二進制數據到瀏覽器。此方法與 render plain:data類似,但也允許您指定瀏覽器 應將響應顯示爲文件附件(即在下載對話框 中)或內嵌數據。您還可以設置內容類型, 明顯的文件名以及其他內容。

角的$http文檔是非常差關於的responseType的$ HTTP的配置。實質上,$ 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); 
    }); 
}; 

角的$http documentation可能是一個多一點的描述比:

使用

$ HTTP(配置);

參數

配置

的responseType - {string}裏 - 看到XMLHttpRequest.responseType

0

我認爲你是在JavaScript解決方案的正確軌道上,但只是有一個錯字。在$http.get調用中,您傳遞一個空對象作爲第二個參數。這是{responseType: arraybuffer}的選項參數應該去的地方。請參閱文檔$http.get此處: https://docs.angularjs.org/api/ng/service/ $ http#得到

相關問題