简体   繁体   English

使用 XMLHttpRequest 下载二进制数据,无需 overrideMimeType

[英]Downloading binary data using XMLHttpRequest, without overrideMimeType

I am trying to retrieve the data of an image in Javascript using XMLHttpRequest .我正在尝试使用XMLHttpRequest在 Javascript 中检索图像数据。

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 ).这个数据的第一个字节应该是0x89 ,但是任何高值字节返回0xfffd0xfffd & 0xff0xfd )。

Questions such as this one offer solutions using the overrideMimeType() function, however this is not supported on the platform I am using (Qt/QML).诸如此类的问题这一个使用提供的解决方案overrideMimeType()函数,但是这是不支持我使用的平台(QT / QML)上。

How can I download the data correctly?如何正确下载数据?

Google I/O 2011: HTML5 Showcase for Web Developers: The Wow and the How Google I/O 2011:面向 Web 开发人员的 HTML5 展示:The Wow 和 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();

Qt version 5.13.1(support native Promise in qml env), prue qml. Qt 版本 5.13.1(支持 qml env 中的原生 Promise),prue qml。

  1. function fetch , like node-fetch函数fetch ,如 node-fetch
  2. function hexdump , dump the data as hex, just use the linux command hexdump to check.功能hexdump ,将数据转储为十六进制,只需使用linux命令hexdump进行检查。
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)=>{

});

I'm not familiarized with Qt but i found this in their documentation我不熟悉 Qt,但我在他们的文档中找到了这个

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:因此,如果您的图像是 png,您可以尝试:

resp = "data:image/png;base64," + btoa(resp);
document.write("<img src=\""+resp+"\">");

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM