当前位置:  开发笔记 > 编程语言 > 正文

如何从IE中的Javascript访问XHR responseBody(二进制数据)?

如何解决《如何从IE中的Javascript访问XHRresponseBody(二进制数据)?》经验,为你挑选了2个好方法。

我有一个使用XMLHttpRequest下载二进制资源的网页.

在Firefox和Gecko中,我可以使用responseText来获取字节,即使字节流包含二进制零.我可能需要强制使用mimetype overrideMimeType()来实现这一点.但是,在IE中,responseText不起作用,因为它似乎终止于第一个零.如果读取100,000个字节,而字节7是二进制零,则只能访问7个字节.IE的XMLHttpRequest公开了一个responseBody访问字节的属性.我已经看到一些帖子暗示直接从Javascript以任何有意义的方式访问这个属性是不可能的.这听起来很疯狂.

xhr.responseBody 从VBScript访问,因此明显的解决方法是在VBScript在网页中定义的方法,然后从JavaScript调用该方法.有关一个示例,请参阅jsdap. 编辑:不要使用这个VBScript !!

var IE_HACK = (/msie/i.test(navigator.userAgent) && 
               !/opera/i.test(navigator.userAgent));   

// no no no!  Don't do this! 
if (IE_HACK) document.write(''); 

var xml = (window.XMLHttpRequest) 
    ? new XMLHttpRequest()      // Mozilla/Safari/IE7+
    : (window.ActiveXObject) 
      ? new ActiveXObject("MSXML2.XMLHTTP")  // IE6
      : null;  // Commodore 64?


xml.open("GET", url, true);
if (xml.overrideMimeType) {
    xml.overrideMimeType('text/plain; charset=x-user-defined');
} else {
    xml.setRequestHeader('Accept-Charset', 'x-user-defined');
}

xml.onreadystatechange = function() {
    if (xml.readyState == 4) {
        if (!binary) {
            callback(xml.responseText);
        } else if (IE_HACK) {
            // call a VBScript method to copy every single byte
            callback(BinaryToArray(xml.responseBody).toArray());
        } else {
            callback(getBuffer(xml.responseText));
        }
    }
};
xml.send('');

这是真的吗?最好的方法?复制每个字节?对于不太高效的大型二进制流.

还有一种可能的技术使用ADODB.Stream,它是一个与MemoryStream等效的COM. 请看这里的例子.它不需要VBScript,但需要单独的COM对象.

if (typeof (ActiveXObject) != "undefined" && typeof (httpRequest.responseBody) != "undefined") {
    // Convert httpRequest.responseBody byte stream to shift_jis encoded string
    var stream = new ActiveXObject("ADODB.Stream");
    stream.Type = 1; // adTypeBinary
    stream.Open ();
    stream.Write (httpRequest.responseBody);
    stream.Position = 0;
    stream.Type = 1; // adTypeBinary;
    stream.Read....          /// ???? what here
}

但是这样做不会很好 - 这些天大多数机器都禁用了ADODB.Stream.


在IE8开发人员工具 - 相当于Firebug的IE中 - 我可以看到responseBody是一个字节数组,我甚至可以看到字节本身.数据就在那里.我不明白为什么我无法达到它.

我可以用responseText读取它吗?

提示?(除了定义VBScript方法)



1> Cheeso..:

是的,我想通过IE中的XHR读取二进制数据的答案就是使用VBScript注入.起初这对我来说是令人讨厌的,但是,我认为它只是一个与浏览器相关的代码.(常规XHR和responseText在其他浏览器中工作正常;您可能必须强制使用mime类型XMLHttpRequest.overrideMimeType().这在IE上不可用).

这就是我得到的东西,就像responseText在IE中一样,即使对于二进制数据也是如此.首先,将一些VBScript作为一次性注入,如下所示:

if(/msie/i.test(navigator.userAgent) && !/opera/i.test(navigator.userAgent)) {
    var IEBinaryToArray_ByteStr_Script =
    "\r\n"+
    "\r\n";

    // inject VBScript
    document.write(IEBinaryToArray_ByteStr_Script);
}

我正在使用的JS类读取二进制文件暴露了一个有趣的方法readCharAt(i),它在第i个索引处读取字符(真正的一个字节).我就是这样设置的:

// see doc on http://msdn.microsoft.com/en-us/library/ms535874(VS.85).aspx
function getXMLHttpRequest() 
{
    if (window.XMLHttpRequest) {
        return new window.XMLHttpRequest;
    }
    else {
        try {
            return new ActiveXObject("MSXML2.XMLHTTP"); 
        }
        catch(ex) {
            return null;
        }
    }
}

// this fn is invoked if IE
function IeBinFileReaderImpl(fileURL){
    this.req = getXMLHttpRequest();
    this.req.open("GET", fileURL, true);
    this.req.setRequestHeader("Accept-Charset", "x-user-defined");
    // my helper to convert from responseBody to a "responseText" like thing
    var convertResponseBodyToText = function (binary) {
        var byteMapping = {};
        for ( var i = 0; i < 256; i++ ) {
            for ( var j = 0; j < 256; j++ ) {
                byteMapping[ String.fromCharCode( i + j * 256 ) ] =
                    String.fromCharCode(i) + String.fromCharCode(j);
            }
        }
        // call into VBScript utility fns
        var rawBytes = IEBinaryToArray_ByteStr(binary);
        var lastChr = IEBinaryToArray_ByteStr_Last(binary);
        return rawBytes.replace(/[\s\S]/g,
                                function( match ) { return byteMapping[match]; }) + lastChr;
    };

    this.req.onreadystatechange = function(event){
        if (that.req.readyState == 4) {
            that.status = "Status: " + that.req.status;
            //that.httpStatus = that.req.status;
            if (that.req.status == 200) {
                // this doesn't work
                //fileContents = that.req.responseBody.toArray(); 

                // this doesn't work
                //fileContents = new VBArray(that.req.responseBody).toArray(); 

                // this works...
                var fileContents = convertResponseBodyToText(that.req.responseBody);

                fileSize = fileContents.length-1;
                if(that.fileSize < 0) throwException(_exception.FileLoadFailed);
                that.readByteAt = function(i){
                    return fileContents.charCodeAt(i) & 0xff;
                };
            }
            if (typeof callback == "function"){ callback(that);}
        }
    };
    this.req.send();
}

// this fn is invoked if non IE
function NormalBinFileReaderImpl(fileURL){
    this.req = new XMLHttpRequest();
    this.req.open('GET', fileURL, true);
    this.req.onreadystatechange = function(aEvt) {
        if (that.req.readyState == 4) {
            if(that.req.status == 200){
                var fileContents = that.req.responseText;
                fileSize = fileContents.length;

                that.readByteAt = function(i){
                    return fileContents.charCodeAt(i) & 0xff;
                }
                if (typeof callback == "function"){ callback(that);}
            }
            else
                throwException(_exception.FileLoadFailed);
        }
    };
    //XHR binary charset opt by Marcus Granado 2006 [http://mgran.blogspot.com] 
    this.req.overrideMimeType('text/plain; charset=x-user-defined');
    this.req.send(null);
}

的转换码被提供Miskun.

非常快,效果很好.

我使用这种方法从Javascript读取和提取zip文件,也在一个用Javascript读取和显示EPUB文件的类中.表现非常合理.500kb文件大约半秒钟.



2> 小智..:

XMLHttpRequest.responseBodyVBArray包含原始字节的对象.您可以使用以下toArray()函数将这些对象转换为标准数组:

var data = xhr.responseBody.toArray();


@timrice:"VBArray"方法不适用于IE8或更早版本.它将抛出"VBArray expected"TypeError.功能检测不起作用,因为IE8上存在"VBArray"对象本身.请盲目地停止传播有缺陷的方法.虽然它适用于IE9及更高版本(即使在IE8模式下),但它并不比"VBScript + CStr"方法快.
谢谢,在IE9(我最低支持的IE版本)中非常适合我,并且是一个更简单的解决方案.
推荐阅读
携手相约幸福
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有