17

I would like to issue a partial content request from an XMLHttpRequest object in javascript. I'm loading a large binary file from the server, and I'd rather stream it from the server similar to how html5 video is handled.

I can use setRequestHeader to set the Range header. The Network inspector in Chrome shows that the Range header is set successfully. However, the Accept-Encoding header is set to "gzip,deflate", and Chrome will not let me set that header (from W3C standards).

Is there any way to force the server to respond with a 206 partial content from the XMLHttpRequest object only from javascript?

jamesshuang
  • 453
  • 1
  • 3
  • 10
  • 1
    Do you program/maintain the server side, too, or do you only do the client side scripting? – Kijewski Mar 22 '13 at 02:05
  • 1
    I would prefer to keep it client-side, although I have access to server-side. I'm coding something that generates a static page that could be uploaded to other hosts, so I'd rather not have to mess with the server side... – jamesshuang Mar 22 '13 at 02:34

2 Answers2

18

This range-request works fine for me: http://jsfiddle.net/QFdU4/

var xhr = new XMLHttpRequest;

xhr.onreadystatechange = function () {
  if (xhr.readyState != 4) {
    return;
  }
  alert(xhr.status);
};

xhr.open('GET', 'http://fiddle.jshell.net/img/logo.png', true);
xhr.setRequestHeader('Range', 'bytes=100-200'); // the bytes (incl.) you request
xhr.send(null);

You have to make sure that the server allows range requests, though. You can test it with curl:

$ curl -v -r 100-200 http://example.com/movie.mkv > /dev/null
Kijewski
  • 25,517
  • 12
  • 101
  • 143
  • 2
    Hmm, that's bizarre. I am also issuing a request to an nginx server. Curl works fine with the -r command. However, when I try that exact code in browser, I only get a 200 response for this large octet-stream (40 mb). Any clues what could be causing that? – jamesshuang Mar 22 '13 at 02:39
  • 1
    Your fiddle response 206. Copy the code and run on my own server, gives 200. What server variables could affect this? – jamesshuang Mar 22 '13 at 02:47
  • 1
    Sorry, I only know about Apache. I did some googling but did not find anything. Maybe your question should better be asked on http://serverfault.com/? – Kijewski Mar 22 '13 at 02:56
12

I think I figured out why the 206 request wasn't working. With gzip compression enabled, the range header gets ignored if the outgoing data can be gzipped.

The file I was requesting was a large binary file, which nginx interpreted as having mimetype application/octet-stream. This is one of the mimetypes that gets gzipped. If I renamed the file to have a .png filetype, the image/png mimetype is not gzipped, and hence the range request works correctly.

This is also why setting the Accept-Encoding header with curl to identity also allows the range request to work fine. However, I cannot change that header from an XHR.

Solution: Change the mimetype table on the server!

jamesshuang
  • 453
  • 1
  • 3
  • 10