AngularJS를 사용하여 ASP.NET 웹 API 메소드에서 파일 다운로드
내 Angular JS 프로젝트에서 <a>
클릭하면 GET
파일을 반환하는 WebAPI 메서드에 HTTP 요청을 하는 앵커 태그 가 있습니다.
이제 요청이 성공하면 파일을 사용자에게 다운로드하고 싶습니다. 어떻게합니까?
앵커 태그 :
<a href="#" ng-click="getthefile()">Download img</a>
AngularJS :
$scope.getthefile = function () {
$http({
method: 'GET',
cache: false,
url: $scope.appPath + 'CourseRegConfirm/getfile',
headers: {
'Content-Type': 'application/json; charset=utf-8'
}
}).success(function (data, status) {
console.log(data); // Displays text data if the file is a text file, binary if it's an image
// What should I write here to download the file I receive from the WebAPI method?
}).error(function (data, status) {
// ...
});
}
내 WebAPI 방법 :
[Authorize]
[Route("getfile")]
public HttpResponseMessage GetTestFile()
{
HttpResponseMessage result = null;
var localFilePath = HttpContext.Current.Server.MapPath("~/timetable.jpg");
if (!File.Exists(localFilePath))
{
result = Request.CreateResponse(HttpStatusCode.Gone);
}
else
{
// Serve the file to the client
result = Request.CreateResponse(HttpStatusCode.OK);
result.Content = new StreamContent(new FileStream(localFilePath, FileMode.Open, FileAccess.Read));
result.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment");
result.Content.Headers.ContentDisposition.FileName = "SampleImg";
}
return result;
}
ajax를 사용하여 이진 파일을 다운로드하는 지원은 크지 않으며 여전히 초안으로 개발되고 있습니다.
간단한 다운로드 방법 :
아래 코드를 사용하여 브라우저가 요청 된 파일을 다운로드하도록 할 수 있으며 모든 브라우저에서 지원되며 WebApi 요청도 동일하게 트리거됩니다.
$scope.downloadFile = function(downloadPath) {
window.open(downloadPath, '_blank', '');
}
아약스 바이너리 다운로드 방법 :
일부 브라우저에서 ajax를 사용하여 이진 파일을 다운로드 할 수 있으며 아래는 Chrome, Internet Explorer, FireFox 및 Safari의 최신 버전에서 작동하는 구현입니다.
arraybuffer
응답 유형을 사용하고 JavaScript로 변환 된 blob
다음 saveBlob
메소드를 사용하여 저장하기 위해 제공됩니다.이 방법은 현재 Internet Explorer에만 존재하지만 브라우저가 여는 BLOB 데이터 URL로 설정되어 트리거됩니다. MIME 유형이 브라우저에서 볼 수 있도록 지원되는 경우 다운로드 대화 상자
Internet Explorer 11 지원 (고정)
참고 : Internet Explorer 11은 msSaveBlob
별명 인 경우이 기능을 사용하는 것을 좋아하지 않았습니다. 보안 기능 일 수도 있지만 결함 일 가능성이 있으므로 사용 var saveBlob = navigator.msSaveBlob || navigator.webkitSaveBlob ... etc.
가능한 saveBlob
지원 을 확인하는 데 사용 하면 예외가 발생했습니다. 따라서 아래 코드가 이제 navigator.msSaveBlob
개별적으로 테스트되는 이유는 무엇입니까? 감사? 마이크로 소프트
// Based on an implementation here: web.student.tuwien.ac.at/~e0427417/jsdownload.html
$scope.downloadFile = function(httpPath) {
// Use an arraybuffer
$http.get(httpPath, { responseType: 'arraybuffer' })
.success( function(data, status, headers) {
var octetStreamMime = 'application/octet-stream';
var success = false;
// Get the headers
headers = headers();
// Get the filename from the x-filename header or default to "download.bin"
var filename = headers['x-filename'] || 'download.bin';
// Determine the content type from the header or default to "application/octet-stream"
var contentType = headers['content-type'] || octetStreamMime;
try
{
// Try using msSaveBlob if supported
console.log("Trying saveBlob method ...");
var blob = new Blob([data], { type: contentType });
if(navigator.msSaveBlob)
navigator.msSaveBlob(blob, filename);
else {
// Try using other saveBlob implementations, if available
var saveBlob = navigator.webkitSaveBlob || navigator.mozSaveBlob || navigator.saveBlob;
if(saveBlob === undefined) throw "Not supported";
saveBlob(blob, filename);
}
console.log("saveBlob succeeded");
success = true;
} catch(ex)
{
console.log("saveBlob method failed with the following exception:");
console.log(ex);
}
if(!success)
{
// Get the blob url creator
var urlCreator = window.URL || window.webkitURL || window.mozURL || window.msURL;
if(urlCreator)
{
// Try to use a download link
var link = document.createElement('a');
if('download' in link)
{
// Try to simulate a click
try
{
// Prepare a blob URL
console.log("Trying download link method with simulated click ...");
var blob = new Blob([data], { type: contentType });
var url = urlCreator.createObjectURL(blob);
link.setAttribute('href', url);
// Set the download attribute (Supported in Chrome 14+ / Firefox 20+)
link.setAttribute("download", filename);
// Simulate clicking the download link
var event = document.createEvent('MouseEvents');
event.initMouseEvent('click', true, true, window, 1, 0, 0, 0, 0, false, false, false, false, 0, null);
link.dispatchEvent(event);
console.log("Download link method with simulated click succeeded");
success = true;
} catch(ex) {
console.log("Download link method with simulated click failed with the following exception:");
console.log(ex);
}
}
if(!success)
{
// Fallback to window.location method
try
{
// Prepare a blob URL
// Use application/octet-stream when using window.location to force download
console.log("Trying download link method with window.location ...");
var blob = new Blob([data], { type: octetStreamMime });
var url = urlCreator.createObjectURL(blob);
window.location = url;
console.log("Download link method with window.location succeeded");
success = true;
} catch(ex) {
console.log("Download link method with window.location failed with the following exception:");
console.log(ex);
}
}
}
}
if(!success)
{
// Fallback to window.open method
console.log("No methods worked for saving the arraybuffer, using last resort window.open");
window.open(httpPath, '_blank', '');
}
})
.error(function(data, status) {
console.log("Request failed with status: " + status);
// Optionally write the error out to scope
$scope.errorDetails = "Request failed with status: " + status;
});
};
용법:
var downloadPath = "/files/instructions.pdf";
$scope.downloadFile(downloadPath);
노트:
다음 헤더를 리턴하도록 WebApi 메소드를 수정해야합니다.
x-filename
헤더를 사용 하여 파일 이름을 보냈습니다. 편의상 사용자 정의 헤더이지만content-disposition
정규 표현식을 사용 하여 헤더 에서 파일 이름을 추출 할 수 있습니다.content-type
응답에 대한 MIME 헤더도 설정해야 브라우저가 데이터 형식을 알 수 있습니다.
이게 도움이 되길 바란다.
C # WebApi PDF 다운로드 Angular JS 인증으로 모든 작업
웹 API 컨트롤러
[HttpGet]
[Authorize]
[Route("OpenFile/{QRFileId}")]
public HttpResponseMessage OpenFile(int QRFileId)
{
QRFileRepository _repo = new QRFileRepository();
var QRFile = _repo.GetQRFileById(QRFileId);
if (QRFile == null)
return new HttpResponseMessage(HttpStatusCode.BadRequest);
string path = ConfigurationManager.AppSettings["QRFolder"] + + QRFile.QRId + @"\" + QRFile.FileName;
if (!File.Exists(path))
return new HttpResponseMessage(HttpStatusCode.BadRequest);
HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK);
//response.Content = new StreamContent(new FileStream(localFilePath, FileMode.Open, FileAccess.Read));
Byte[] bytes = File.ReadAllBytes(path);
//String file = Convert.ToBase64String(bytes);
response.Content = new ByteArrayContent(bytes);
response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
response.Content.Headers.ContentDisposition.FileName = QRFile.FileName;
return response;
}
각도 JS 서비스
this.getPDF = function (apiUrl) {
var headers = {};
headers.Authorization = 'Bearer ' + sessionStorage.tokenKey;
var deferred = $q.defer();
$http.get(
hostApiUrl + apiUrl,
{
responseType: 'arraybuffer',
headers: headers
})
.success(function (result, status, headers) {
deferred.resolve(result);;
})
.error(function (data, status) {
console.log("Request failed with status: " + status);
});
return deferred.promise;
}
this.getPDF2 = function (apiUrl) {
var promise = $http({
method: 'GET',
url: hostApiUrl + apiUrl,
headers: { 'Authorization': 'Bearer ' + sessionStorage.tokenKey },
responseType: 'arraybuffer'
});
promise.success(function (data) {
return data;
}).error(function (data, status) {
console.log("Request failed with status: " + status);
});
return promise;
}
어느 쪽이든
서비스를 호출하는 Angular JS Controller
vm.open3 = function () {
var downloadedData = crudService.getPDF('ClientQRDetails/openfile/29');
downloadedData.then(function (result) {
var file = new Blob([result], { type: 'application/pdf;base64' });
var fileURL = window.URL.createObjectURL(file);
var seconds = new Date().getTime() / 1000;
var fileName = "cert" + parseInt(seconds) + ".pdf";
var a = document.createElement("a");
document.body.appendChild(a);
a.style = "display: none";
a.href = fileURL;
a.download = fileName;
a.click();
});
};
마지막 HTML 페이지
<a class="btn btn-primary" ng-click="vm.open3()">FILE Http with crud service (3 getPDF)</a>
이것은 코드를 공유하는 것만으로 리팩토링 될 것입니다.이 작업을 수행하는 데 시간이 걸리는 누군가를 돕기를 바랍니다.
나를 위해 웹 API는 Restangular 및 FileSaver.js 와 함께 사용되는 Rails 및 클라이언트 측 Angular 였습니다.
웹 API
module Api
module V1
class DownloadsController < BaseController
def show
@download = Download.find(params[:id])
send_data @download.blob_data
end
end
end
end
HTML
<a ng-click="download('foo')">download presentation</a>
앵귤러 컨트롤러
$scope.download = function(type) {
return Download.get(type);
};
각도 서비스
'use strict';
app.service('Download', function Download(Restangular) {
this.get = function(id) {
return Restangular.one('api/v1/downloads', id).withHttpConfig({responseType: 'arraybuffer'}).get().then(function(data){
console.log(data)
var blob = new Blob([data], {
type: "application/pdf"
});
//saveAs provided by FileSaver.js
saveAs(blob, id + '.pdf');
})
}
});
또한 인증 이 필요한 API에서도 작동하는 솔루션을 개발해야했습니다 ( 이 기사 참조 ).
간단히 말해서 AngularJS를 사용하는 방법은 다음과 같습니다.
1 단계 : 전용 지시문 작성
// jQuery needed, uses Bootstrap classes, adjust the path of templateUrl
app.directive('pdfDownload', function() {
return {
restrict: 'E',
templateUrl: '/path/to/pdfDownload.tpl.html',
scope: true,
link: function(scope, element, attr) {
var anchor = element.children()[0];
// When the download starts, disable the link
scope.$on('download-start', function() {
$(anchor).attr('disabled', 'disabled');
});
// When the download finishes, attach the data to the link. Enable the link and change its appearance.
scope.$on('downloaded', function(event, data) {
$(anchor).attr({
href: 'data:application/pdf;base64,' + data,
download: attr.filename
})
.removeAttr('disabled')
.text('Save')
.removeClass('btn-primary')
.addClass('btn-success');
// Also overwrite the download pdf function to do nothing.
scope.downloadPdf = function() {
};
});
},
controller: ['$scope', '$attrs', '$http', function($scope, $attrs, $http) {
$scope.downloadPdf = function() {
$scope.$emit('download-start');
$http.get($attrs.url).then(function(response) {
$scope.$emit('downloaded', response.data);
});
};
}]
});
2 단계 : 템플릿 만들기
<a href="" class="btn btn-primary" ng-click="downloadPdf()">Download</a>
3 단계 : 사용
<pdf-download url="/some/path/to/a.pdf" filename="my-awesome-pdf"></pdf-download>
This will render a blue button. When clicked, a PDF will be downloaded (Caution: the backend has to deliver the PDF in Base64 encoding!) and put into the href. The button turns green and switches the text to Save. The user can click again and will be presented with a standard download file dialog for the file my-awesome.pdf.
Send your file as a base64 string.
var element = angular.element('<a/>');
element.attr({
href: 'data:attachment/csv;charset=utf-8,' + encodeURI(atob(response.payload)),
target: '_blank',
download: fname
})[0].click();
If attr method not working in Firefox You can also use javaScript setAttribute method
You could implement a showfile function which takes in parameters of the data returned from the WEBApi, and a filename for the file you are trying to download. What I did was create a separate browser service identifies the user's browser and then handles the rendering of the file based on the browser. For instance if the target browser is chrome on an ipad, you have to use javascripts FileReader object.
FileService.showFile = function (data, fileName) {
var blob = new Blob([data], { type: 'application/pdf' });
if (BrowserService.isIE()) {
window.navigator.msSaveOrOpenBlob(blob, fileName);
}
else if (BrowserService.isChromeIos()) {
loadFileBlobFileReader(window, blob, fileName);
}
else if (BrowserService.isIOS() || BrowserService.isAndroid()) {
var url = URL.createObjectURL(blob);
window.location.href = url;
window.document.title = fileName;
} else {
var url = URL.createObjectURL(blob);
loadReportBrowser(url, window,fileName);
}
}
function loadFileBrowser(url, window, fileName) {
var iframe = window.document.createElement('iframe');
iframe.src = url
iframe.width = '100%';
iframe.height = '100%';
iframe.style.border = 'none';
window.document.title = fileName;
window.document.body.appendChild(iframe)
window.document.body.style.margin = 0;
}
function loadFileBlobFileReader(window, blob,fileName) {
var reader = new FileReader();
reader.onload = function (e) {
var bdata = btoa(reader.result);
var datauri = 'data:application/pdf;base64,' + bdata;
window.location.href = datauri;
window.document.title = fileName;
}
reader.readAsBinaryString(blob);
}
In your component i.e angular js code:
function getthefile (){
window.location.href='http://localhost:1036/CourseRegConfirm/getfile';
};
I have gone through array of solutions and this is what I found to have worked great for me.
In my case I needed to send a post request with some credentials. Small overhead was to add jquery inside the script. But was worth it.
var printPDF = function () {
//prevent double sending
var sendz = {};
sendz.action = "Print";
sendz.url = "api/Print";
jQuery('<form action="' + sendz.url + '" method="POST">' +
'<input type="hidden" name="action" value="Print" />'+
'<input type="hidden" name="userID" value="'+$scope.user.userID+'" />'+
'<input type="hidden" name="ApiKey" value="' + $scope.user.ApiKey+'" />'+
'</form>').appendTo('body').submit().remove();
}
'IT story' 카테고리의 다른 글
Vim에서 regexp의 \ b와 같은 단어 경계 문자를 어떻게 검색합니까? (0) | 2020.06.30 |
---|---|
파이썬에서 화면을 지우는 방법 (0) | 2020.06.30 |
C #의 임의 날짜 (0) | 2020.06.30 |
각도 필터로 데이터를 그룹화하려면 어떻게해야합니까? (0) | 2020.06.30 |
파이썬 스레딩 문자열 인수 (0) | 2020.06.30 |