An issue arises when interpreting binary data as text. When the server responds with
Content-Type: application/octet-stream
, it does not specify the encoding explicitly. Consequently, the browser assumes UTF-8 encoding for the data. While most bytes (0 to 127) are interpreted as single characters in UTF-8, higher value bytes are often replaced by a replacement character. However, valid multi-byte UTF-8 sequences within your binary file will be combined into one character, causing discrepancies between the length of
responseText
and the actual number of bytes received from the server.
To address this issue, you can enforce a specific encoding using the request.overrideMimeType()
method. For example, specifying ISO 8859-1 may ensure that each byte is treated as a single character:
request.overrideMimeType("application/octet-stream; charset=iso-8859-1");
Alternatively, storing the server response in an ArrayBuffer
specifically designed for handling binary data would provide a more robust solution:
var request = new XMLHttpRequest();
request.open(...);
request.responseType = "arraybuffer";
request.send();
...
var array = new Uint8Array(request.response);
alert("First byte has value " + array[0]);
alert("Array length is " + array.length);
As per MDN, setting responseType = "arraybuffer"
is supported in Chrome 10, Firefox 6, and Internet Explorer 10. Refer to Typed arrays for additional information.
Note: Firefox also supports
responseType = "moz-chunked-text"
and
responseType = "moz-chunked-arraybuffer"
from version 9 onwards for receiving data in chunks without relying on ranged requests. Whereas Chrome is prioritizing implementation of the
Streams API instead of these options.
Edit: Chrome's possible misrepresentation of response headers was not replicated without sample code. The potential culprit could be found in function partial_data.cc:
// We are making multiple requests to complete the range requested by the user.
// Just assume that everything is fine and say that we are returning what was
// requested.
void PartialData::FixResponseHeaders(HttpResponseHeaders* headers,
bool success) {
if (truncated_)
return;
if (byte_range_.IsValid() && success) {
headers->UpdateWithNewRange(byte_range_, resource_size_, !sparse_entry_);
return;
}
This code snippet alters the returned Content-Length
and Content-Range
headers based on request parameters, potentially leading to mismatches. If experiencing issues, consider clearing the cache or verifying the accuracy of the resource_size_
variable against the actual file size indicated by the server response.