I'm trying to download the first 1 MB of data from a file from an URL using fetch API in JavaScript, after 1 MB I'm not interested in the remaining data and I wish to stop the browser from downloading any of it.
I have tried the following code:
async function download(url, maxBytes) {
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error('Network response was not ok');
}
const reader = response.body.getReader();
let bytesRead = 0;
let chunks = [];
while (bytesRead < maxBytes) {
const { done, value } = await reader.read();
if (done) { break; }
chunks.push(value);
bytesRead += value.length;
}
reader.cancel("Download size limit reached.");
const result = new Uint8Array(bytesRead);
let offset = 0;
for (const chunk of chunks) {
result.set(chunk, offset);
offset += chunk.length;
}
let str = (new TextDecoder().decode(result));
// stuff to do with the str here
} catch (error) {
console.error('Error downloading the file:', error);
}
}
download('https://speed.hetzner.de/1GB.bin', 2000000);
// Test file, random data of 1 GB size
// 2000000 bytes should be close to 2 MB
The issue with it is that it'll work the first time, but after it won't work when using it again on the same URL.
I'd like to suggest as an alternative approach to simply ask in your request for a Byte-Range by adding the corresponding header:
const response = await fetch(url, {headers: {Range: 'bytes=0-' + (maxBytes-1)}});
This will certainly work, if the server supports Byte-Ranges and if the file is bigger than your maxBytes. If the file is smaller, I'm not sure if the server might respond with an error, if you demand more bytes. It might still work, but to be on the safe side, one could first make a HEAD-request via fetch with the options {method: HEAD}
, in order to get the content-length from the response headers and afterwards ask for the Byte-Range as described above.
If Byte-Ranges are not supported by the Server you could also stick to your approach, as there now seems to be a way to send an abort-signal to the fetch connection. This is described in the accepted answer to the question, how to cancel a fetch-request