If I want to download a file, what should I do in the then
block below?
function downloadFile(token, fileId) {
let url = `https://www.googleapis.com/drive/v2/files/${fileId}?alt=media`;
return fetch(url, {
method: 'GET',
headers: {
'Authorization': token
}
}).then(...);
}
Note the codes are in client-side.
I temporarily solve this problem by using download.js and blob
.
let download = require('./download.min');
...
function downloadFile(token, fileId) {
let url = `https://www.googleapis.com/drive/v2/files/${fileId}?alt=media`;
return fetch(url, {
method: 'GET',
headers: {
'Authorization': token
}
}).then(function(resp) {
return resp.blob();
}).then(function(blob) {
download(blob);
});
}
It's working for small files, but maybe not working for large files. I think I should dig Stream more.
Using dowloadjs. This will parse the filename from the header.
fetch("yourURL", {
method: "POST",
body: JSON.stringify(search),
headers: {
"Content-Type": "application/json; charset=utf-8"
}
})
.then(response => {
if (response.status === 200) {
filename = response.headers.get("content-disposition");
filename = filename.match(/(?<=")(?:\\.|[^"\\])*(?=")/)[0];
return response.blob();
} else {
return;
}
})
.then(body => {
download(body, filename, "application/octet-stream");
});
};
This is more shorter and efficient, no libraries only fetch API
const url ='http://sample.example.file.doc'
const authHeader ="Bearer 6Q************"
const options = {
headers: {
Authorization: authHeader
}
};
fetch(url, options)
.then( res => res.blob() )
.then( blob => {
var file = window.URL.createObjectURL(blob);
window.location.assign(file);
});
I tried window.fetch but that ended up being complicated with my REACT app
now i just change window.location.href and add query params like the jsonwebtoken
and other stuff
.
///==== client side code =====
var url = new URL(`http://${process.env.REACT_APP_URL}/api/mix-sheets/list`);
url.searchParams.append("interval",data.interval);
url.searchParams.append("jwt",token)
window.location.href=url;
// ===== server side code =====
// on the server i set the content disposition to a file
var list = encodeToCsv(dataToEncode);
res.set({"Content-Disposition":`attachment; filename=\"FileName.csv\"`});
res.status(200).send(list)
the end results actually end up being pretty nice, the window makes request and downloads the file and doesn't event switch move the page away, its as if the window.location.href
call was like a lowkey fetch()
call.
As per some of the other answers, you can definitely use window.fetch and download.js to download a file. However, using window.fetch with blob has the restriction on memory imposed by the browser, and the download.js also has its compatibility restrictions.
If you need to download a big-sized file, you don't want to put it in the memory of the client side to stress the browser, right? Instead, you probably prefer to download it via a stream. In such a case, using an HTML link to download a file is one of the best/simplest ways, especially for downloading big-sized files via a stream.
Step One: create and style a link element
You can make the link invisible but still actionable.
HTML:
<a href="#" class="download-link" download>Download</a>
CSS:
.download-link {
position: absolute;
top: -9999px;
left: -9999px;
opacity: 0;
}
Step Two: Set the href
of the link, and trigger the click
event
JavaScript
let url = `https://www.googleapis.com/drive/v2/files/${fileId}?alt=media`;
const downloadLink = document.querySelector('.download-link')
downloadLink.href = url + '&ts=' + new Date().getTime() // Prevent cache
downloadLink.click()
Note: you can dynamically generate the link element if necessary.
EDIT: syg answer is better. Just use downloadjs library.
The answer I provided works well on Chrome, but on Firefox and IE you need some different variant of this code. It's better to use library for that.
I had similar problem (need to pass authorization header to download a file so this solution didn't helped).
But based on this answer you can use createObjectURL
to make browser save a file downloaded by Fetch API.
getAuthToken()
.then(token => {
fetch("http://example.com/ExportExcel", {
method: 'GET',
headers: new Headers({
"Authorization": "Bearer " + token
})
})
.then(response => response.blob())
.then(blob => {
var url = window.URL.createObjectURL(blob);
var a = document.createElement('a');
a.href = url;
a.download = "filename.xlsx";
document.body.appendChild(a); // we need to append the element to the dom -> otherwise it will not work in firefox
a.click();
a.remove(); //afterwards we remove the element again
});
});
function download(dataurl, filename) {
var a = document.createElement("a");
a.href = dataurl;
a.setAttribute("download", filename);
a.click();
return false;
}
download("data:text/html,HelloWorld!", "helloWorld.txt");
or:
function download(url, filename) {
fetch(url).then(function(t) {
return t.blob().then((b)=>{
var a = document.createElement("a");
a.href = URL.createObjectURL(b);
a.setAttribute("download", filename);
a.click();
}
);
});
}
download("https://get.geojs.io/v1/ip/geo.json","geoip.json")
download("data:text/html,HelloWorld!", "helloWorld.txt");
Here is an example using node-fetch for anyone that finds this.
reportRunner({url, params = {}}) {
let urlWithParams = `${url}?`
Object.keys(params).forEach((key) => urlWithParams += `&${key}=${params[key]}`)
return fetch(urlWithParams)
.then(async res => ({
filename: res.headers.get('content-disposition').split('filename=')[1],
blob: await res.blob()
}))
.catch(this.handleError)
}
©2020 All rights reserved.