Downloading binary data using XMLHttpRequest, without overrideMimeType
I am trying to retrieve the data of an image in Javascript using XMLHttpRequest
.
var xhr = new XMLHttpRequest();
xhr.open("GET", "http://www.celticfc.net/images/doc/celticcrest.png");
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
开发者_开发知识库 var resp = xhr.responseText;
console.log(resp.charCodeAt(0) & 0xff);
}
};
xhr.send();
The first byte of this data should be 0x89
, however any high-value bytes return as 0xfffd
(0xfffd & 0xff
being 0xfd
).
Questions such as this one offer solutions using the overrideMimeType()
function, however this is not supported on the platform I am using (Qt/QML).
How can I download the data correctly?
Google I/O 2011: HTML5 Showcase for Web Developers: The Wow and the How
Fetch binary file: new hotness
var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://www.celticfc.net/images/doc/celticcrest.png', true);
xhr.responseType = 'arraybuffer';
xhr.onload = function(e) {
if (this.status == 200) {
var uInt8Array = new Uint8Array(this.response); // Note:not xhr.responseText
for (var i = 0, len = uInt8Array.length; i < len; ++i) {
uInt8Array[i] = this.response[i];
}
var byte3 = uInt8Array[4]; // byte at offset 4
}
}
xhr.send();
I'm not familiarized with Qt but i found this in their documentation
string Qt::btoa ( data )
Binary to ASCII - this function returns a base64 encoding of data.
So, if your image is a png you can try:
resp = "data:image/png;base64," + btoa(resp);
document.write("<img src=\""+resp+"\">");
Qt version 5.13.1(support native Promise in qml env), prue qml.
- function
fetch
, like node-fetch - function
hexdump
, dump the data as hex, just use the linux commandhexdump
to check.
function createResponse(xhr) {
let res = {};
function headersParser() {
let headersRaw = {};
let lowerCaseHeaders = {};
let rawHeaderArray = xhr.getAllResponseHeaders().split("\n");
for(let i in rawHeaderArray) {
let rawHeader = rawHeaderArray[i];
let headerItem = rawHeader.split(":");
let name = headerItem[0].trim();
let value = headerItem[1].trim();
let lowerName = name.toLowerCase();
headersRaw[name] = value;
lowerCaseHeaders [lowerName] = value;
}
return {
"headersRaw": headersRaw,
"lowerCaseHeaders": lowerCaseHeaders
};
}
res.headers = {
__alreayParse : false,
raw: function() {
if (!res.headers.__alreayParse) {
let {headersRaw, lowerCaseHeaders} = headersParser();
res.headers.__alreayParse = true;
res.headers.__headersRaw = headersRaw;
res.headers.__lowerCaseHeaders = lowerCaseHeaders;
}
return res.headers.__headersRaw;
},
get: function(headerName) {
if (!res.headers.__alreayParse) {
let {headersRaw, lowerCaseHeaders} = headersParser();
res.headers.__alreayParse = true;
res.headers.__headersRaw = headersRaw;
res.headers.__lowerCaseHeaders = lowerCaseHeaders;
}
return res.headers.__lowerCaseHeaders[headerName.toLowerCase()];
}
};
res.json = function() {
if(res.__json) {
return res.__json;
}
return res.__json = JSON.parse(xhr.responseText);
}
res.text = function() {
if (res.__text) {
return res.__text;
}
return res.__text = xhr.responseText;
}
res.arrayBuffer = function() {
if (res.__arrayBuffer) {
return res.__arrayBuffer;
}
return res.__arrayBuffer = new Uint8Array(xhr.response);
}
res.ok = (xhr.status >= 200 && xhr.status < 300);
res.status = xhr.status;
res.statusText = xhr.statusText;
return res;
}
function fetch(url, options) {
return new Promise(function(resolve, reject) {
let requestUrl = "";
let method = "";
let headers = {};
let body;
let timeout;
if (typeof url === 'string') {
requestUrl = url;
method = "GET";
if (options) {
requestUrl = options['url'];
method = options['method'];
headers = options['headers'];
body = options['body'];
timeout = options['timeout'];
}
} else {
let optionsObj = url;
requestUrl = optionsObj['url'];
method = optionsObj['method'];
headers = optionsObj['headers'];
body = optionsObj['body'];
timeout = optionsObj['timeout'];
}
let xhr = new XMLHttpRequest;
if (timeout) {
xhr.timeout = timeout;
}
// must set responseType to arraybuffer, then the xhr.response type will be ArrayBuffer
// but responseType not effect the responseText
xhr.responseType = 'arraybuffer';
xhr.onreadystatechange = function() {
// readyState as follow: UNSENT, OPENED, HEADERS_RECEIVED, LOADING, DONE
if(xhr.readyState === XMLHttpRequest.DONE) {
resolve(createResponse(xhr));
}
};
xhr.open(method, requestUrl);
// todo check headers
for(var iter in headers) {
xhr.setRequestHeader(iter, headers[iter]);
}
if("GET" === method || "HEAD" === method) {
xhr.send();
} else {
xhr.send(body);
}
});
}
function hexdump(uint8array) {
let count = 0;
let line = "";
let lineCount = 0;
let content = "";
for(let i=0; i<uint8array.byteLength; i++) {
let c = uint8array[i];
let hex = c.toString(16).padStart (2, "0");
line += hex + " ";
count++;
if (count === 16) {
let lineCountHex = (lineCount).toString (16).padStart (7, "0") + "0";
content += lineCountHex + " " + line + "\n";
line = "";
count = 0;
lineCount++;
}
}
if(line) {
let lineCountHex = (lineCount).toString (16).padStart (7, "0") + "0";
content += lineCountHex + " " + line + "\n";
line = "";
// count = 0;
lineCount++;
}
content+= (lineCount).toString (16).padStart (7, "0") + count.toString(16) +"\n";
return content;
}
fetch("https://avatars2.githubusercontent.com/u/6630355")
.then((res)=>{
try {
let headers = res.headers.raw();
console.info(`headers:`, JSON.stringify(headers));
let uint8array = res.arrayBuffer();
let hex = hexdump(uint8array);
console.info(hex)
}catch(error) {
console.trace(error);
}
})
.catch((error)=>{
});
精彩评论