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

2023-05-16前端开发问题
16

本文介绍了如何在 IE 中从 Javascript 访问 XHR responseBody(用于二进制数据)?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着跟版网的小编来一起学习吧!

问题描述

限时送ChatGPT账号..

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

I've got a web page that uses XMLHttpRequest to download a binary resource.

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

In Firefox and Gecko I can use responseText to get the bytes, even if the bytestream includes binary zeroes. I may need to coerce the mimetype with overrideMimeType() to make that happen. In IE, though, responseText doesn't work, because it appears to terminate at the first zero. If you read 100,000 bytes, and byte 7 is a binary zero, you will be able to access only 7 bytes. IE's XMLHttpRequest exposes a responseBody property to access the bytes. I've seen a few posts suggesting that it's impossible to access this property in any meaningful way directly from Javascript. This sounds crazy to me.

xhr.responseBody 可从 VBScript 访问,因此显而易见的解决方法是在网页的 VBScript 中定义一个方法,然后从 Javascript 调用该方法.例如,请参阅 jsdap.不要使用这个 VBScript!!

xhr.responseBody is accessible from VBScript, so the obvious workaround is to define a method in VBScript in the webpage, and then call that method from Javascript. See jsdap for one example. DO NOT USE THIS 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('<script type="text/vbscript">

     Function BinaryToArray(Binary)

         Dim i

         ReDim byteArray(LenB(Binary))

         For i = 1 To LenB(Binary)

             byteArray(i-1) = AscB(MidB(Binary, i, 1))

         Next

         BinaryToArray = byteArray

     End Function

</script>'); 

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('');

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

Is this really true? The best way? copying every byte? For a large binary stream that's not going to be very efficient.

还有一个可能技术使用 ADODB.Stream,它是一个 COM 等效的 MemoryStream.参见此处 示例.它不需要 VBScript,但需要一个单独的 COM 对象.

There is also a possible technique using ADODB.Stream, which is a COM equivalent of a MemoryStream. See here for an example. It does not require VBScript but does require a separate COM object.

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.

But that's not going to work well - ADODB.Stream is disabled on most machines these days.

在 IE8 开发人员工具(相当于 Firebug 的 IE)中,我可以看到 responseBody 是一个字节数组,我什至可以看到字节本身.数据就在那儿.我不明白为什么我做不到.

In The IE8 developer tools - the IE equivalent of Firebug - I can see the responseBody is an array of bytes and I can even see the bytes themselves. The data is right there. I don't understand why I can't get to it.

我可以用 responseText 阅读它吗?

Is it possible for me to read it with responseText?

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

hints? (other than defining a VBScript method)

推荐答案

是的,我在IE中通过XHR读取二进制数据的方法是使用VBScript注入.起初这对我来说很反感,但是,我将其视为更多依赖于浏览器的代码.(常规的 XHR 和 responseText 在其他浏览器中运行良好;您可能必须使用 强制 mime 类型XMLHttpRequest.overrideMimeType().这在 IE 上不可用).

Yes, the answer I came up with for reading binary data via XHR in IE, is to use VBScript injection. This was distasteful to me at first, but, I look at it as just one more browser dependent bit of code. (The regular XHR and responseText works fine in other browsers; you may have to coerce the mime type with XMLHttpRequest.overrideMimeType(). This isn't available on IE).

这就是我如何在 IE 中获得类似于 responseText 的东西,即使对于二进制数据也是如此.首先,一次性注入一些 VBScript,如下所示:

This is how I got a thing that works like responseText in IE, even for binary data. First, inject some VBScript as a one-time thing, like this:

if(/msie/i.test(navigator.userAgent) && !/opera/i.test(navigator.userAgent)) {
    var IEBinaryToArray_ByteStr_Script =
    "<!-- IEBinaryToArray_ByteStr -->
"+
    "<script type='text/vbscript' language='VBScript'>
"+
    "Function IEBinaryToArray_ByteStr(Binary)
"+
    "   IEBinaryToArray_ByteStr = CStr(Binary)
"+
    "End Function
"+
    "Function IEBinaryToArray_ByteStr_Last(Binary)
"+
    "   Dim lastIndex
"+
    "   lastIndex = LenB(Binary)
"+
    "   if lastIndex mod 2 Then
"+
    "       IEBinaryToArray_ByteStr_Last = Chr( AscB( MidB( Binary, lastIndex, 1 ) ) )
"+
    "   Else
"+
    "       IEBinaryToArray_ByteStr_Last = "+'""'+"
"+
    "   End If
"+
    "End Function
"+
    "</script>
";

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

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

The JS class I'm using that reads binary files exposes a single interesting method, readCharAt(i), which reads the character (a byte, really) at the i'th index. This is how I set it up:

// 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(/[sS]/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 的文件大约需要半秒.

I used this method to read and extract zip files from Javascript, and also in a class that reads and displays EPUB files in Javascript. Very reasonable performance. About half a second for a 500kb file.

这篇关于如何在 IE 中从 Javascript 访问 XHR responseBody(用于二进制数据)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!

The End

相关推荐

js删除数组中指定元素的5种方法
在JavaScript中,我们有多种方法可以删除数组中的指定元素。以下给出了5种常见的方法并提供了相应的代码示例: 1.使用splice()方法: let array = [0, 1, 2, 3, 4, 5];let index = array.indexOf(2);if (index -1) { array.splice(index, 1);}// array = [0,...
2024-11-22 前端开发问题
182

JavaScript小数运算出现多位的解决办法
在开发JS过程中,会经常遇到两个小数相运算的情况,但是运算结果却与预期不同,调试一下发现计算结果竟然有那么长一串尾巴。如下图所示: 产生原因: JavaScript对小数运算会先转成二进制,运算完毕再转回十进制,过程中会有丢失,不过不是所有的小数间运算会...
2024-10-18 前端开发问题
301

JavaScript(js)文件字符串中丢失"\"斜线的解决方法
问题描述: 在javascript中引用js代码,然后导致反斜杠丢失,发现字符串中的所有\信息丢失。比如在js中引用input type=text onkeyup=value=value.replace(/[^\d]/g,) ,结果导致正则表达式中的\丢失。 问题原因: 该字符串含有\,javascript对字符串进行了转...
2024-10-17 前端开发问题
437

layui中table列表 增加属性 edit="date",不生效怎么办?
如果你想在 layui 的 table 列表中增加 edit=date 属性但不生效,可能是以下问题导致的: 1. 缺少日期组件的初始化 如果想在表格中使用日期组件,需要在页面中引入 layui 的日期组件,并初始化: script type="text/javascript" src="/layui/layui.js"/scrip...
2024-06-11 前端开发问题
455

正则表达式([A-Za-z])为啥可以匹配字母加数字或特殊符号?
问题描述: 我需要在我的应用程序中验证一个文本字段。它既不能包含数字,也不能包含特殊字符,所以我尝试了这个正则表达式:/[a-zA-Z]/匹配,问题是,当我在字符串的中间或结尾放入一个数字或特殊字符时,这个正则表达式依然可以匹配通过。 解决办法: 你应...
2024-06-06 前端开发问题
165

Rails/Javascript:如何将 rails 变量注入(非常)简单的 javascript
Rails/Javascript: How to inject rails variables into (very) simple javascript(Rails/Javascript:如何将 rails 变量注入(非常)简单的 javascript)...
2024-04-20 前端开发问题
5