28

Basically, I want to figure out whether I should download a file using AJAX, depending on how large the filesize is.

I guess this question could also be rephrased as: How do I get only the header of an ajax request?


EDIT: ultima-rat0 in the comments told me of two questions that had already been asked that apparently are the same as this one. They are very similar, but they both want jQuery. I want a non-jQuery solution to this.

4

4 Answers 4

44

You can get XHR response header data manually:

http://www.w3.org/TR/XMLHttpRequest/#the-getresponseheader()-method

This function will get the filesize of the requested URL:

function get_filesize(url, callback) { var xhr = new XMLHttpRequest(); xhr.open("HEAD", url, true); // Notice "HEAD" instead of "GET", // to get only the header xhr.onreadystatechange = function() { if (this.readyState == this.DONE) { callback(parseInt(xhr.getResponseHeader("Content-Length"))); } }; xhr.send(); } get_filesize("http://example.com/foo.exe", function(size) { alert("The size of foo.exe is: " + size + " bytes."); }); 
Sign up to request clarification or add additional context in comments.

5 Comments

And if I used a variable instead of alert? Why they return 'undefined'? How can i store xhr.getResponseHeader("Content-Length") in a variable?
@FabioCalvosa xhr.open("HEAD", url, true); // false makes the request asynchronous So when you call that function like this: var myVar; get_filesize('sample.com'); alert(myVar); // your variable is 'undefined' But if you change your code like this: var myVar; get_filesize('sample.com', function(){ alert(myVar); // your variable will not be 'undefined' be cause you call a call back method });
I called it in Chrome console, but it got NaN.
readyState when headers are available could be sooner with HEADERS_RECEIVED
thank you! It's helps me Content-Length
3

Sometimes HEAD can act differently than GET so I suggest something like this that aborts the request after getting Content-Length header:

new Promise(resolve => { var xhr = new XMLHttpRequest(); xhr.open('GET', '/a.bin', true); xhr.onreadystatechange = () => { resolve(+xhr.getResponseHeader("Content-Length")); xhr.abort(); }; xhr.send(); }).then(console.log); 

1 Comment

What if Content-Length is less than what is actually received in the response body? Is there a way to get the uncompressed size of the response from the server?
2

If HEAD request is not possible:

The solution Ebrahim did only not work in firefox for me because context-length was not available for aborted request in firefox. So I used 'onprogress' event instead of 'onreadystatechange' event:

new Promise( (resolve, reject) => { var xhr = new XMLHttpRequest(); xhr.open('GET', url, true); xhr.onprogress = (event) => { if (event.lengthComputable) { resolve(event.total); } else { reject(new Error('No content-length available')); } xhr.abort(); }; xhr.send(); } ); 

Comments

1

1) If only headers are needed, 'HEAD' should be always preferred over 'GET' because of a simple but not widely known detail: Even if you use 'GET' and immediately abort on readyState === 2 (as suggested by other answers), you will have already received not only the headers, but the full first chunk of information (headers + part of the body) that can vary in size, but usually transfer size will be at least doubled unnecessarily. Using 'HEAD' instead, you can be sure that only headers will be transferred.

2) Content-Length header must be exposed by 'Access-Control-Expose-Headers' to be accessible client-side. If you are dealing with multiple origin resources and you are not sure if Content-Length has been exposed, to prevent exceptions, you can check that, inside an event handler, like this (or other many different ways):

let contentLength = null; if (checkHeaders(e.target, ['*','Content-Length'])) { // YOU CAN ACCESS HEADER contentLength = parseInt(e.target.getResponseHeader("Content-Length")); } else { // YOU CAN NOT ACCESS HEADER console.log('Content-Length NOT AVAILABLE'); } function checkHeaders(request, headers) { return (headers.some(function (elem) { return (request.getResponseHeader("Access-Control-Expose-Headers").includes(elem)); })); } 

3) Content-Length header IS NOT forbidden when any type of encoding is applied (as suggested in some comments). But, be careful that Content-Length will be usually the size of the decoded body (even if it should not). This can be prevented in many different ways, but it is a server-side consideration.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.