How do I load binary image data using Javascript and XMLHttpRequest?
I was trying to load an image client side and base64 encode the bytes returned by the server in order to pass it off to perform some processing. IE has a RequestBody property of the XMLHttpRequest object, but I can't seem to use it, and RequestText is truncated. In Firefox, RequestText is there, but seems corrupted.
Here's how I did it.
This technique is provided in an answer to another SO question, but it's also relevant here.
I didn't want to base64 encode anything. I wanted to download and parse binary files in the browser via Javascript, without modifying the server to encode them specially. I found that in Firefox, by coercing the mimetype of the response via overrideMimeType()
, I could use XMLHttpRequest.responseText
. On IE, it's different because:
responseText
on IE truncates at the first zero. For binary streams this is a big problem.
there is no XMLHttpRequest.overrideMimeType()
, to force IE to treat binary streams as text.
while there is a XMLHttpRequest.responseBody
(IE only!) that is specifically designed to be used with binary data streams, maddeningly that property is not usable from Javascript.
Therefore, the need is to convert IE's responseBody
property into a thing that looks like responseText
from FireFox, with the mime-type coercion. This is possible using injected VBScript.
To make it cross-browser, you need to just pack up the browser-specific logic in a conditional. This is what I used:
// one-time code
if(/msie/i.test(navigator.userAgent) && !/opera/i.test(navigator.userAgent)) {
var IEBinaryToArray_ByteStr_Script =
"<!-- IEBinaryToArray_ByteStr -->rn"+
"<script type='text/vbscript'>rn"+
"Function IEBinaryToArray_ByteStr(Binary)rn"+
" IEBinaryToArray_ByteStr = CStr(Binary)rn"+
"End Functionrn"+
"Function IEBinaryToArray_ByteStr_Last(Binary)rn"+
" Dim lastIndexrn"+
" lastIndex = LenB(Binary)rn"+
" if lastIndex mod 2 Thenrn"+
" IEBinaryToArray_ByteStr_Last = Chr( AscB( MidB( Binary, lastIndex, 1 ) ) )rn"+
" Elsern"+
" IEBinaryToArray_ByteStr_Last = "+'""'+"rn"+
" End Ifrn"+
"End Functionrn"+
"</script>rn";
// inject VBScript
document.write(IEBinaryToArray_ByteStr_Script);
}
// each time you make a request for a binary resource:
var req = (function() {
if (window.XMLHttpRequest) {
return new window.XMLHttpRequest();
}
else {
try {
return new ActiveXObject("MSXML2.XMLHTTP");
}
catch(ex) {
return null;
}
}
})();
var fileContents = "";
var filesize = -1;
var readByteAt = function(i){
return fileContents.charCodeAt(i) & 0xff;
};
req.open("GET", url, true);
if(/msie/i.test(navigator.userAgent) && !/opera/i.test(navigator.userAgent)) {
// IE-specific logic here
// 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);
}
}
var rawBytes = IEBinaryToArray_ByteStr(binary);
var lastChr = IEBinaryToArray_ByteStr_Last(binary);
return rawBytes.replace(/[sS]/g,
function( match ) { return byteMapping[match]; }) + lastChr;
};
req.setRequestHeader("Accept-Charset", "x-user-defined");
req.onreadystatechange = function(event){
if (req.readyState == 4) {
if (req.status == 200) {
fileContents = convertResponseBodyToText(req.responseBody);
fileSize = fileContents.length-1;
// invoke a callback here, if you like...
}
else{
alert("download failed, status " + req.status);
}
}
};
req.send();
} else {
// ff/Gecko/Webkit specific stuff here
req.onreadystatechange = function(aEvt) {
if (req.readyState == 4) { // completed
if(req.status == 200){ // status == OK
fileContents = binStream.req.responseText;
filesize = fileContents.length;
// invoke a callback here, if you like...
}
else {
alert("download failed, status " + req.status);
}
}
};
// coerce response type
req.overrideMimeType('text/plain; charset=x-user-defined');
req.send(null);
}
...then call readByte(i)
to get the byte at the ith position in the binary file.
Good luck.
Credit to Miskun for the VBScript conversion logic.
如果你使用的是COTS,你总是可以建立一个中间网关,在这个网关中,请求被创建和转换(在这种情况下是base64编码),然后返回给客户端,再转变为更美味的东西。
You could have the server return base64 text, rather than doing that encoding client side.
For example, (in ASP.NET) a request to /ImageAsBase64.ashx?file=/images/myimage.png could be coded to read the file, base64encode it, and stream it as a response.
It's really going to be pretty much the same thing in PHP or whatever.
链接地址: http://www.djcxy.com/p/71744.html