javascript - readasdataurl - fileReader.readAsBinaryString para cargar archivos
read file javascript (3)
Intentando usar fileReader.readAsBinaryString para cargar un archivo PNG al servidor a través de AJAX, código eliminado (fileObject es el objeto que contiene información en mi archivo);
var fileReader = new FileReader();
fileReader.onload = function(e) {
var xmlHttpRequest = new XMLHttpRequest();
//Some AJAX-y stuff - callbacks, handlers etc.
xmlHttpRequest.open("POST", ''/pushfile'', true);
var dashes = ''--'';
var boundary = ''aperturephotoupload'';
var crlf = "/r/n";
//Post with the correct MIME type (If the OS can identify one)
if ( fileObject.type == '''' ){
filetype = ''application/octet-stream'';
} else {
filetype = fileObject.type;
}
//Build a HTTP request to post the file
var data = dashes + boundary + crlf + "Content-Disposition: form-data;" + "name=/"file/";" + "filename=/"" + unescape(encodeURIComponent(fileObject.name)) + "/"" + crlf + "Content-Type: " + filetype + crlf + crlf + e.target.result + crlf + dashes + boundary + dashes;
xmlHttpRequest.setRequestHeader("Content-Type", "multipart/form-data;boundary=" + boundary);
//Send the binary data
xmlHttpRequest.send(data);
}
fileReader.readAsBinaryString(fileObject);
Examinar las primeras líneas de un archivo antes de subir (usando VI) me da
El mismo archivo después de la carga muestra
Parece un problema de formateo / codificación en alguna parte, intenté usar una función de codificación UTF8 simple en los datos binarios en bruto
function utf8encode(string) {
string = string.replace(//r/n/g,"/n");
var utftext = "";
for (var n = 0; n < string.length; n++) {
var c = string.charCodeAt(n);
if (c < 128) {
utftext += String.fromCharCode(c);
}
else if((c > 127) && (c < 2048)) {
utftext += String.fromCharCode((c >> 6) | 192);
utftext += String.fromCharCode((c & 63) | 128);
}
else {
utftext += String.fromCharCode((c >> 12) | 224);
utftext += String.fromCharCode(((c >> 6) & 63) | 128);
utftext += String.fromCharCode((c & 63) | 128);
}
}
return utftext;
)
Luego en el código original
//Build a HTTP request to post the file
var data = dashes + boundary + crlf + "Content-Disposition: form-data;" + "name=/"file/";" + "filename=/"" + unescape(encodeURIComponent(file.file.name)) + "/"" + crlf + "Content-Type: " + filetype + crlf + crlf + utf8encode(e.target.result) + crlf + dashes + boundary + dashes;
que me da la salida de
Todavía no es lo que era el archivo sin procesar = (
¿Cómo puedo codificar / cargar / procesar el archivo para evitar los problemas de codificación, por lo que el archivo que se recibe en la solicitud HTTP es el mismo que el del archivo antes de que se cargara?
Otra información posiblemente útil, si en lugar de usar fileReader.readAsBinaryString () utilizo fileObject.getAsBinary () para obtener los datos binarios, funciona bien. Pero getAsBinary solo funciona en Firefox. He estado probando esto en Firefox y Chrome, ambos en Mac, obteniendo el mismo resultado en ambos. Las cargas de back-end son manejadas por el Módulo de carga NGINX , que nuevamente se ejecuta en Mac. El servidor y el cliente están en la misma máquina. Lo mismo está sucediendo con cualquier archivo que intento subir, simplemente elegí PNG porque era el ejemplo más obvio.
(A continuación se encuentra una respuesta tardía pero completa)
Soporte de métodos FileReader
FileReader.readAsBinaryString()
está en desuso. ¡No lo uses! Ya no está en el borrador de trabajo de W3C File API :
void abort();
void readAsArrayBuffer(Blob blob);
void readAsText(Blob blob, optional DOMString encoding);
void readAsDataURL(Blob blob);
NB: Tenga en cuenta que File
es un tipo de estructura Blob
extendida.
Mozilla todavía implementa readAsBinaryString()
y lo describe en la documentación de MDN FileApi :
void abort();
void readAsArrayBuffer(in Blob blob); Requires Gecko 7.0
void readAsBinaryString(in Blob blob);
void readAsDataURL(in Blob file);
void readAsText(in Blob blob, [optional] in DOMString encoding);
La razón detrás de la readAsBinaryString()
es, en mi opinión, la siguiente: el estándar para cadenas de JavaScript son DOMString
que solo aceptan caracteres UTF-8, NO datos binarios aleatorios. Entonces no use readAsBinaryString (), eso no es seguro y cumple con ECMAScript.
Sabemos que las cadenas de JavaScript no deben almacenar datos binarios, pero Mozilla puede hacerlo de alguna forma. Eso es peligroso en mi opinión. Blob
y typed arrays
( ArrayBuffer
y el ArrayBuffer
aún no implementado pero no necesario) se inventaron para un propósito: permitir el uso de datos binarios puros, sin restricciones de cadenas UTF-8.
Soporte de carga XMLHttpRequest
XMLHttpRequest.send()
tiene las siguientes opciones de invocaciones:
void send();
void send(ArrayBuffer data);
void send(Blob data);
void send(Document data);
void send(DOMString? data);
void send(FormData data);
XMLHttpRequest.sendAsBinary()
tiene las siguientes opciones de invocaciones:
void sendAsBinary( in DOMString body );
sendAsBinary () NO es un estándar y es posible que no sea compatible con Chrome.
Soluciones
Entonces tienes varias opciones:
-
send()
FileReader.result
deFileReader.readAsArrayBuffer ( fileObject )
. Es más complicado de manipular (tendrá que enviar un send () por separado), pero es el ENFOQUE RECOMENDADO . -
send()
FileReader.result
deFileReader.readAsDataURL( fileObject )
. Genera sobrecarga inútil y latencia de compresión, requiere un paso de descompresión en el lado del servidor PERO es fácil de manipular como una cadena en Javascript. - Siendo no estándar y
sendAsBinary()
elFileReader.result
deFileReader.readAsBinaryString( fileObject )
XMLHttpRequest.send() declara que:
La mejor manera de enviar contenido binario (como en la carga de archivos) es utilizar ArrayBuffers o Blobs en conjunción con el método send (). Sin embargo, si desea enviar datos brutos codificables, utilice en su lugar el método sendAsBinary () o la superclase de arreglos StringView (no nativos).
La mejor forma en los navegadores que lo soportan es enviar el archivo como un Blob o usar FormData si desea un formulario de varias partes. No necesita un FileReader para eso. Esto es más simple y más eficiente que tratar de leer los datos.
Si desea enviarlo específicamente como multipart/form-data
, puede usar un objeto FormData:
var xmlHttpRequest = new XMLHttpRequest();
xmlHttpRequest.open("POST", ''/pushfile'', true);
var formData = new FormData();
// This should automatically set the file name and type.
formData.append("file", file);
// Sending FormData automatically sets the Content-Type header to multipart/form-data
xmlHttpRequest.send(formData);
También puede enviar los datos directamente, en lugar de usar multipart/form-data
. Ver la documentation . Por supuesto, esto también necesitará un cambio en el lado del servidor.
// file is an instance of File, e.g. from a file input.
var xmlHttpRequest = new XMLHttpRequest();
xmlHttpRequest.open("POST", ''/pushfile'', true);
xmlHttpRequest.setRequestHeader("Content-Type", file.type);
// Send the binary data.
// Since a File is a Blob, we can send it directly.
xmlHttpRequest.send(file);
Para obtener ayuda con el navegador, consulte: http://caniuse.com/#feat=xhr2 (la mayoría de los navegadores, incluido IE 10+).
Use fileReader.readAsDataURL( fileObject )
, esto lo codificará en base64, que puede cargar de forma segura en su servidor.