I had an endpoint on .Net server
[HttpPost]
[Route("api/tagExportSelectedToExcel")]
and a React frontend with axios. The task was to add a button which downloads a file from this API. I spent several hours before found this solution. I hope it will be helpful for someone else.
This is what I did:
axios('/api/tagExportSelectedToExcel', {
data: exportFilter,
method: 'POST',
responseType: 'blob'
}).then(res => resolveAndDownloadBlob(res));
Where resolveAndDownloadBlob:
/**
* Resolved and downloads blob response as a file.
* FOR BROWSERS ONLY
* @param response
*/
function resolveAndDownloadBlob(response: any) {
let filename = 'tags.xlsx';
filename = decodeURI(filename);
const url = window.URL.createObjectURL(new Blob([response.data]));
const link = document.createElement('a');
link.href = url;
link.setAttribute('download', filename);
document.body.appendChild(link);
link.click();
window.URL.revokeObjectURL(url);
link.remove();
}
Answer from Michael Klishevich on Stack OverflowI had an endpoint on .Net server
[HttpPost]
[Route("api/tagExportSelectedToExcel")]
and a React frontend with axios. The task was to add a button which downloads a file from this API. I spent several hours before found this solution. I hope it will be helpful for someone else.
This is what I did:
axios('/api/tagExportSelectedToExcel', {
data: exportFilter,
method: 'POST',
responseType: 'blob'
}).then(res => resolveAndDownloadBlob(res));
Where resolveAndDownloadBlob:
/**
* Resolved and downloads blob response as a file.
* FOR BROWSERS ONLY
* @param response
*/
function resolveAndDownloadBlob(response: any) {
let filename = 'tags.xlsx';
filename = decodeURI(filename);
const url = window.URL.createObjectURL(new Blob([response.data]));
const link = document.createElement('a');
link.href = url;
link.setAttribute('download', filename);
document.body.appendChild(link);
link.click();
window.URL.revokeObjectURL(url);
link.remove();
}
My first guess would be: Just request that API URL directly and not with an asynchronous request. You should be able to do something like this in your code
$window.location = "http://example.org/api/download"
For a solution using RESTangular I found this snipped, maybe you can try it:
Restangular.one('attachments', idAtt).withHttpConfig({responseType: 'blob'}}.get({}, {"X-Auth-Token": 'token'}).then(function(response) {
var url = (window.URL || window.webkitURL).createObjectURL(response);
window.open(url);
});
javascript - Implement file download from REST service in webapp - Stack Overflow
javascript - Get File and download from rest api - Stack Overflow
jquery - How to download a file from a RESTful API? - Stack Overflow
sharepoint server - Download file using REST - SharePoint Stack Exchange
Videos
I think you could using blob, something like
var content=...the content of your request;
var mypdf = new Blob(content, {type : 'application/pdf'});
and check answer from "panzi" in this other question Using HTML5/Javascript to generate and save a file
(One character per element in the array seem pretty nice binary. Probably you don't need to transform it. https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Sending_and_Receiving_Binary_Data )
Maybe you could do something like this?
var a = document.createElement('a');
a.href = 'data:attachment/pdf,' + encodeURI(data);
a.target = '_blank';
a.download = 'filename.pdf';
a.click();
You'd just have to make sure that data was in the correct format, which IIRC is base64.
$('#your_button').click(function(){
window.open('http://localhost:xxxx/xx.xml');
return false;
});
if you have control over the webhost, send the header:
Content-disposition: attachment; filename=x.xml
You could also use AJAX call and something like the downloadify flash object. Other than these there is no native way to force the downloading of a file
I usually use AttachmentFiles endpoint to do this, it is provided when you create or select Item with API.
<link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/AttachmentFiles" type="application/atom+xml;type=feed" title="AttachmentFiles" href="Web/Lists(guid'12f9fd2c-0eea-4440-b9d3-a6e445839ba3')/Items(66)/AttachmentFiles" />
Main part is
href="Web/Lists(guid'12f9fd2c-0eea-4440-b9d3-a6e445839ba3')/Items(66)/AttachmentFiles"
You can use both
To download /Items(66)/AttachmentFiles('file.docx')
To upload /Items(66)/AttachmentFiles/add(FileName='file.docx')
Then u can use a GET method to download file content :
executor.executeAsync(
{
url: UsePreviousEndPoint,
type: "GET",
contentType: "application/atom+xml;type=entry",
headers: {
"Accept": "application/atom+xml",
"Authorization": "Bearer " + UserOrAppToken
},
success: function (blobURL)
{
SaveToDisk_blob(blobURL, fileName)
},
error: function (xhr)
{
console.log(xhr);
console.log("downloadFile" + xhr.status + ": " + xhr.statusText);
}
});
I guess Digest is only mandatory for POST request.
below are my final working code for downloading file from REST.
var dfd = $.Deferred();
var xhr = new XMLHttpRequest();
xhr.open("GET", filepath);
xhr.responseType = "blob";
//setting response-type header to be blob so that we get the file as blob
xhr.onload = function ()
{
//async call
var blobobj = xhr.response;
window.navigator.msSaveBlob(blobobj, fileName);
//save using msSaveBlob.
dfd.resolve(true);
}
xhr.send();
return dfd.promise()
I'm working with an API res that contains a zip, csv, and pdf. I've been researching how I should download and/or create download buttons for these files but a lot of articles I'm looking through specify that their method is 'hacky' (or something similar).
I don't like the idea of pushing a 'hacky' solution to production. It may be a starting point but not really a good foundation to build off of. Does anybody know of good practices for this kind of procedure?
I've boiled it down to:
-
Parse the response
-
Store the file contents
-
Create sources for the downloads
but surely it isn't that simple, right?
Advice is simple: you cannot download files via AJAX - it's a security policy. I mean you can download the data, but you can't save it to disk from JavaScript side.
If you want to download a file on click, then you can just add href to you a tag. Or open a new window with file's URL.
A) you don't have a callback to receive data back
b) Add error callback to you code so you can see if there are receiving errors after the call:
$.ajax({
url: '/spaconsole/rest/examples/getcode',
type: 'POST'
success: function (data) {
console.log('ok');
},
error: function (xhr) {
console.log(xhr);
}
});
Edit: This is if you want to display the text in page. If you want to download the file, this is not the way, you cannot use ajax