I am receiving a ReadableStream from a server, returned from my fetch call.
A ReadableStream is returned but I don’t know how to trigger a download from this stage. I can’t use the url in an href because it requires an Authorization token.
I don’t want to install fs
on the client so what options do I have?
try { const res = await fetch(url, { method: 'GET', headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/octet-stream' } }); const blob = await res.blob(); const newBlob = new Blob([blob]); const newUrl = window.URL.createObjectURL(newBlob); const link = document.createElement('a'); link.href = newUrl; link.setAttribute('download', 'filename'); document.body.appendChild(link); link.click(); link.parentNode.removeChild(link); window.URL.revokeObjectURL(newBlob); } catch (error) { console.log(error); }
Update 1
I converted the file to a Blob, then passed it into a newly generated href. Successfully downloaded a file. The end result was the ReadStream contents as a .txt file.
Meaning stuff like this
x:ÚêÒÓ%¶âÜTb∞܃
Advertisement
Answer
I have found 2 solutions, both worked but I was missing a simple addition to make them work.
The native solution is
try { const res = await fetch(url, { method: 'GET', headers: { Authorization: `Bearer ${token}` } }); const blob = await res.blob(); const newBlob = new Blob([blob]); const blobUrl = window.URL.createObjectURL(newBlob); const link = document.createElement('a'); link.href = blobUrl; link.setAttribute('download', `${filename}.${extension}`); document.body.appendChild(link); link.click(); link.parentNode.removeChild(link); // clean up Url window.URL.revokeObjectURL(blobUrl);
This version is using the npm package steamSaver for anyone who would prefer it.
try { const res = await fetch(url, { method: 'GET', headers: { Authorization: `Bearer ${token}` } }); const fileStream = streamSaver.createWriteStream(`${filename}.${extension}`); const writer = fileStream.getWriter(); const reader = res.body.getReader(); const pump = () => reader.read() .then(({ value, done }) => { if (done) writer.close(); else { writer.write(value); return writer.ready.then(pump); } }); await pump() .then(() => console.log('Closed the stream, Done writing')) .catch(err => console.log(err));
The key for why it was not working was because I did not include the extension, so it either errored out because of the mimetype was wrong or it opens a .txt file with a string of the body instead of the image.