Я пытался загрузить клиентскую часть изображения, а base64 кодировал байты, возвращаемые сервером, чтобы передать его для выполнения некоторой обработки. IE имеет свойство RequestBody объекта XMLHttpRequest, но я не могу его использовать, и RequestText усечен. В Firefox есть RequestText, но кажется поврежденным.
Как загрузить данные двоичного изображения с помощью Javascript и XMLHttpRequest?
Ответ 1
Вот как я это сделал.
Этот метод предоставляется в ответе на другой вопрос SO, но он также имеет значение здесь.
Я не хотел, чтобы base64 закодировал что-нибудь. Я хотел загрузить и разбор бинарных файлов в браузере с помощью Javascript, не изменяя сервер, чтобы их кодировать специально. Я обнаружил, что в Firefox, при помощи mimetype ответа через overrideMimeType()
, я мог бы использовать XMLHttpRequest.responseText
. В IE это отличается тем, что:
-
responseText
на IE усекает при первом нуле. Для двоичных потоков это большая проблема. -
нет
XMLHttpRequest.overrideMimeType()
, чтобы заставить IE обрабатывать двоичные потоки как текст. -
в то время как существует
XMLHttpRequest.responseBody
(только IE!), специально разработанный для использования с бинарными потоками данных, безумно, что свойство не может использоваться из Javascript.
Следовательно, необходимо преобразовать свойство IE responseBody
в вещь, которая выглядит как responseText
из FireFox, с принуждением типа mime. Это возможно, используя вложенный VBScript.
Чтобы сделать это кросс-браузером, вам нужно просто собрать логику, зависящую от браузера, в условном выражении. Это то, что я использовал:
// one-time code
if(/msie/i.test(navigator.userAgent) && !/opera/i.test(navigator.userAgent)) {
var IEBinaryToArray_ByteStr_Script =
"<!-- IEBinaryToArray_ByteStr -->\r\n"+
"<script type='text/vbscript'>\r\n"+
"Function IEBinaryToArray_ByteStr(Binary)\r\n"+
" IEBinaryToArray_ByteStr = CStr(Binary)\r\n"+
"End Function\r\n"+
"Function IEBinaryToArray_ByteStr_Last(Binary)\r\n"+
" Dim lastIndex\r\n"+
" lastIndex = LenB(Binary)\r\n"+
" if lastIndex mod 2 Then\r\n"+
" IEBinaryToArray_ByteStr_Last = Chr( AscB( MidB( Binary, lastIndex, 1 ) ) )\r\n"+
" Else\r\n"+
" IEBinaryToArray_ByteStr_Last = "+'""'+"\r\n"+
" End If\r\n"+
"End Function\r\n"+
"</script>\r\n";
// 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(/[\s\S]/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);
}
... затем вызовите readByte(i)
, чтобы получить байт в i-й позиции в двоичном файле.
Удачи.
Кредит Miskun для логики преобразования VBScript.
Ответ 2
Если вы используете COTS, вы всегда можете настроить промежуточный шлюз, в котором запрос выполняется и преобразуется (в этом случае кодируется base64) во что-то более приятное, прежде чем он будет возвращен клиенту.
Ответ 3
Вы могли бы вернуть серверный текст base64, а не делать эту клиентскую сторону для кодирования.
Например, (в ASP.NET) запрос /ImageAsBase 64.ashx?file=/images/myimage.png может быть закодирован, чтобы прочитать файл, base64encode и передать его в качестве ответа.
Это действительно будет почти то же самое в PHP или что-то еще.