問題描述
我有一個(gè)使用 XMLHttpRequest<的網(wǎng)頁/a> 下載二進(jìn)制資源.
I've got a web page that uses XMLHttpRequest to download a binary resource.
在 Firefox 和 Gecko 中,我可以使用 responseText 來獲取字節(jié),即使字節(jié)流包含二進(jìn)制零.我可能需要用 overrideMimeType()
強(qiáng)制 mimetype 來實(shí)現(xiàn)這一點(diǎn).但是,在 IE 中,responseText 不起作用,因?yàn)樗坪踉诘谝粋€(gè)零處終止.如果您讀取 100,000 個(gè)字節(jié),并且字節(jié) 7 是二進(jìn)制零,您將只能訪問 7 個(gè)字節(jié).IE 的 XMLHttpRequest 公開了一個(gè) responseBody
屬性來訪問字節(jié).我看過一些帖子表明不可能直接從 Javascript 以任何有意義的方式訪問此屬性.這對(duì)我來說聽起來很瘋狂.
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 訪問,因此顯而易見的解決方法是在網(wǎng)頁的 VBScript 中定義一個(gè)方法,然后從 Javascript 調(diào)用該方法.例如,請(qǐng)參閱 jsdap.不要使用這個(gè) 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('');
這是真的嗎?最好的方法?復(fù)制每個(gè)字節(jié)?對(duì)于不會(huì)非常有效的大型二進(jìn)制流.
Is this really true? The best way? copying every byte? For a large binary stream that's not going to be very efficient.
還有一個(gè)可能技術(shù)使用 ADODB.Stream,它是一個(gè) COM 等效的 MemoryStream.參見此處 示例.它不需要 VBScript,但需要一個(gè)單獨(dú)的 COM 對(duì)象.
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
}
但這不會(huì)很好地工作 - 現(xiàn)在大多數(shù)機(jī)器上都禁用了 ADODB.Stream.
But that's not going to work well - ADODB.Stream is disabled on most machines these days.
在 IE8 開發(fā)人員工具(相當(dāng)于 Firebug 的 IE)中,我可以看到 responseBody 是一個(gè)字節(jié)數(shù)組,我什至可以看到字節(jié)本身.數(shù)據(jù)就在那兒.我不明白為什么我做不到.
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?
提示?(除了定義一個(gè) VBScript 方法)
hints? (other than defining a VBScript method)
推薦答案
是的,我在IE中通過XHR讀取二進(jìn)制數(shù)據(jù)的方法是使用VBScript注入.起初這對(duì)我來說很反感,但是,我將其視為更多依賴于瀏覽器的代碼.(常規(guī)的 XHR 和 responseText 在其他瀏覽器中運(yùn)行良好;您可能必須使用 強(qiáng)制 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
的東西,即使對(duì)于二進(jìn)制數(shù)據(jù)也是如此.首先,一次性注入一些 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);
}
我正在使用的讀取二進(jìn)制文件的 JS 類公開了一個(gè)有趣的方法,readCharAt(i)
,它讀取第 i 個(gè)索引處的字符(實(shí)際上是一個(gè)字節(jié)).我是這樣設(shè)置的:
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);
}
轉(zhuǎn)換碼由Miskun提供.
非常快,效果很好.
我使用這種方法從 Javascript 中讀取和提取 zip 文件,并在一個(gè)用 Javascript 讀取和顯示 EPUB 文件的類中.很合理的表現(xiàn).一個(gè) 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.
這篇關(guān)于如何在 IE 中從 Javascript 訪問 XHR responseBody(用于二進(jìn)制數(shù)據(jù))?的文章就介紹到這了,希望我們推薦的答案對(duì)大家有所幫助,也希望大家多多支持html5模板網(wǎng)!