How to show download progress in browser's built in download manager
I am writing a react web app and I need to download files from presigned S3 urls (or a zip from streamed from Fastapi if need be).
I want use the built in download manager UI that modern browsers have to show the download is in progress, the same way that the AWS S3 Console web app does but I cannot figure it out.
Here's what I'm looking for... here
Here's my current code...
for (const asset of data) {
setCurrentAsset(data.indexOf(asset) + 1);
const s3Response = await fetch(asset.url);
if (!s3Response.ok) {
alert(`Failed to download: ${asset.name}`, );
break;
}
const chunks = [];
const reader = s3Response.body!.getReader();
const contentLength = +(s3Response.headers.get('Content-Length'))!;
let totalDownloaded = 0;
while (true) {
const { done, value } = await reader!.read();
if (done) {
break;
}
chunks.push(value);
totalDownloaded += value!.length;
setPercentThrottled(Math.round(totalDownloaded / contentLength * 100));
}
const url = window.URL.createObjectURL(new Blob(chunks));
const a = document.createElement('a');
a.href = url;
a.download = asset.name;
document.body.appendChild(a);
a.click();
window.URL.revokeObjectURL(url);
document.body.removeChild(a);
}
}
The assets appear in the download manager after all of the chunks have been streamed in, but I want to see the download as it progresses in the download manager.
Further, my backend is Fastapi. I've also used its StreamingResponse
class to stream a zip
of the assets in one file and that did not solve the problem.
Answer
What you're asking for isn't possible.
Browsers currently do not expose APIs to file download progress in their download managers. By the time you use createObjectURL
, the object has already been downloaded in the browser and is ready to write to the filesystem, so it doesn't make sense for the download manager to show download progress in this instance. Your only option with this implementation is to show download progress in the webpage after each read of the stream, like you're already doing.
You're likely misunderstanding the job that the S3 Console website performs. All it does when you click the Download button is generate its own presigned URL and has the browser download it as if you clicked a direct link. You'll need to do something similar in your FastAPI endpoints using boto3. Once done, you can pass the generated URL back to your browser, and then do something similar to what you're already doing in the bottom of your code block, create an anchor element (maybe in a shadow DOM so it's not visible in the page at any time), set the href to your generated URL, and click it.