Stavo cercando di caricare un lato client dell'immagine e base64 codifica i byte restituiti dal server per passarlo a eseguire qualche elaborazione. IE ha una proprietà RequestBody dell'oggetto XMLHttpRequest, ma non riesco a usarlo, e RequestText viene troncato. In Firefox, RequestText è presente, ma sembra danneggiato.Come caricare i dati di immagine binaria utilizzando Javascript e XMLHttpRequest?
risposta
È possibile che il server restituisca il testo base64, anziché eseguire tale codifica client.
Ad esempio, (in ASP.NET) una richiesta a /ImageAsBase64.ashx?file=/images/myimage.png potrebbe essere codificata per leggere il file, base64encode, e trasmetterlo in streaming come risposta.
In pratica sarà praticamente la stessa cosa in PHP o altro.
Sfortunatamente, in questo scenario non funzionerebbe, avevo bisogno di dati da qualche software COTS, e non aveva un'opzione base64. –
Se si utilizza COTS, è sempre possibile impostare un gateway intermedio in cui la richiesta viene effettuata e trasformata (codificata Base64 in questo caso) in qualcosa di più appetibile prima di essere restituita al client.
In realtà ho provato questo; tuttavia, le immagini erano specifiche per la sessione dell'utente e non ero in grado di simulare il software per pensare che il server fosse parte della stessa sessione utente. –
Ecco come l'ho fatto.
Questa tecnica viene fornita in risposta a un'altra domanda SO, ma è anche rilevante qui.
Non volevo codificare in base64 nulla. Volevo scaricare e analizzare i file binari nel browser tramite Javascript, senza modificare il server per codificarli appositamente. Ho scoperto che in Firefox, forzando il mimetype della risposta tramite overrideMimeType()
, potrei usare XMLHttpRequest.responseText
. Su IE, è diverso perché:
responseText
su IE tronca al primo zero. Per i flussi binari questo è un grosso problema.non c'è
XMLHttpRequest.overrideMimeType()
, per forzare IE a trattare i flussi binari come testo.mentre c'è uno
XMLHttpRequest.responseBody
(solo IE!) Che è specificamente progettato per essere utilizzato con flussi di dati binari, esasperatamente che la proprietà non è utilizzabile da Javascript.
Pertanto, la necessità è quella di convertire la proprietà di IE responseBody
in una cosa che assomiglia responseText
da Firefox, con il mime-type coercizione. Questo è possibile usando VBScript iniettato.
Per renderlo cross-browser, è necessario solo impacchettare la logica specifica del browser in modo condizionale. Questo è quello che ho usato:
// 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);
}
... quindi chiamare readByte(i)
per ottenere il byte nella posizione esimo nel file binario.
Buona fortuna.
Credit to Miskun per la logica di conversione VBScript.
Dopo alcuni giorni di sforzi, sono riuscito a farlo funzionare, anche se le informazioni su Internet per fare una tale manipolazione binaria sono abbastanza scarse. Penso che possa essere utile per gli altri, specialmente quando si tratta di URI di dati, quindi ho dettagliato il mio lavoro qui: [http://emilsblog.lerch.org/2009/07/javascript-hacks-using-xhr-to- load.html] (http: //emilsblog.lerch.org/2009/07/javascript-hacks-using-xhr-to-load.html) –