In mijn Angular JS-project heb ik een <a>
-ankertag, die wanneer erop wordt geklikt een HTTP GET
-verzoek doet aan een WebAPI-methode die een bestand retourneert .
Nu wil ik dat het bestand naar de gebruiker wordt gedownload zodra het verzoek is gelukt. Hoe doe ik dat?
De ankertag:
<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) {
// ...
});
}
Mijn WebAPI-methode:
[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;
}
Antwoord 1, autoriteit 100%
Ondersteuning voor het downloaden van binaire bestanden in het gebruik van ajax is niet geweldig, het is nog steeds in ontwikkeling als werkende concepten.
Eenvoudige downloadmethode:
Je kunt de browser het gevraagde bestand laten downloaden door simpelweg de onderstaande code te gebruiken, en dit wordt ondersteund in alle browsers, en zal uiteraard het WebApi-verzoek op dezelfde manier activeren.
$scope.downloadFile = function(downloadPath) {
window.open(downloadPath, '_blank', '');
}
Ajax binaire downloadmethode:
Ajax gebruiken om het binaire bestand te downloaden kan in sommige browsers en hieronder is een implementatie die zal werken in de nieuwste versies van Chrome, Internet Explorer, FireFox en Safari.
Het gebruikt een arraybuffer
-antwoordtype, dat vervolgens wordt omgezet in een JavaScript blob
, die vervolgens wordt gepresenteerd om op te slaan met behulp van de saveBlob
methode – hoewel dit momenteel alleen aanwezig is in Internet Explorer – of omgezet in een blob-gegevens-URL die wordt geopend door de browser, waardoor het downloaddialoogvenster wordt geactiveerd als het mime-type wordt ondersteund voor weergave in de browser.
Internet Explorer 11-ondersteuning (vast)
Opmerking: Internet Explorer 11 hield er niet van om de functie msSaveBlob
te gebruiken als deze onder een alias was gezet – misschien een beveiligingsfunctie, maar waarschijnlijker een fout, dus het gebruik van var saveBlob = navigator.msSaveBlob || navigator.webkitSaveBlob ... etc.
om de beschikbare saveBlob
-ondersteuning te bepalen, veroorzaakte een uitzondering; daarom test de onderstaande code nu afzonderlijk voor navigator.msSaveBlob
. Bedankt? Microsoft
// 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;
});
};
Gebruik:
var downloadPath = "/files/instructions.pdf";
$scope.downloadFile(downloadPath);
Opmerkingen:
U moet uw WebApi-methode aanpassen om de volgende koppen te retourneren:
-
Ik heb de
x-filename
header gebruikt om de bestandsnaam te verzenden. Dit is voor het gemak een aangepaste header, maar u kunt de bestandsnaam uit decontent-disposition
-header halen met behulp van reguliere expressies. -
U moet ook de
content-type
mime-header voor uw reactie instellen, zodat de browser het gegevensformaat kent.
Ik hoop dat dit helpt.
Antwoord 2, autoriteit 4%
C# WebApi PDF-download die allemaal werkt met Angular JS-authenticatie
Web API-controller
[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;
}
Angular JS-service
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;
}
Een van beide is voldoende
Angular JS-controller die de service aanroept
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();
});
};
En als laatste de HTML-pagina
<a class="btn btn-primary" ng-click="vm.open3()">FILE Http with crud service (3 getPDF)</a>
Dit wordt aangepast door de code te delen, nu hoop ik dat iemand er iets aan heeft, want het heeft even geduurd voordat ik dit werkend kreeg.
Antwoord 3, autoriteit 2%
Voor mij was de Web API Rails en client-side Angular gebruikt met Restangularen FileSaver.js
Web-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>
Hoekcontroller
$scope.download = function(type) {
return Download.get(type);
};
Angulaire service
'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');
})
}
});