Tratando de usar fileReader.readAsBinaryString para cargar un archivo PNG con el servidor a través de AJAX, despojado de código (fileObject es el objeto que contiene la 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);

El examen de las primeras líneas de un archivo antes de subir (utilizando VI) me da

fileReader.readAsBinaryString para subir archivos

El mismo archivo después de la carga se muestra

fileReader.readAsBinaryString para subir archivos

Por lo que se ve como un formato de codificación problema en algún lugar, he intentado utilizar un simple UTF8 codificar función de los datos binarios puros

    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;
    )

A continuación, 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

fileReader.readAsBinaryString para subir archivos

Todavía no es lo que el archivo raw =(

¿Cómo puedo codificar/carga/proceso del archivo para evitar los problemas de codificación, por lo que el archivo que está siendo recibido en la petición HTTP es el mismo que el archivo antes de que se haya cargado.

Algunos otros, posiblemente, información útil, si en lugar de utilizar fileReader.readAsBinaryString() yo uso fileObject.getAsBinary() para obtener los datos binarios, funciona bien. Pero getAsBinary sólo funciona en Firefox. He estado probando esto en Firefox y Chrome, tanto en Mac, obteniendo el mismo resultado en ambos. El backend para las cargas manejadas por el NGINX el Módulo de Carga de, de nuevo se ejecutan en Mac. El servidor y el cliente están en la misma máquina. Lo mismo está sucediendo con cualquier archivo de trato de subir, yo sólo eligió PNG porque era el ejemplo más obvio.

InformationsquelleAutor Smudge | 2011-09-15

3 Comentarios

  1. 70

    Uso fileReader.readAsDataURL( fileObject ), esto va a codificar en base64, que con seguridad puede subir a su servidor.

    • Mientras que funciona, la versión de los archivos guardados en el servidor está codificado en Base64 (como debe ser). No hay manera de transferir como datos binarios en lugar de la codificación Base64 (I. E. como si hubiese sido cargado utilizando una normal <input type="file"> campo)
    • Si usted tiene PHP en el servidor, puede base64_decode(archivo) antes de guardarlo. Y no hay ninguna forma segura para la transferencia de datos binarios puros a través de http.
    • El uso de readAsDataURL me da este imgur.com/1LHya en el servidor, corriendo hacia atrás a través de PHP, base64_decode (en realidad estamos usando Python, pero PHP es una buena prueba) I get imgur.com/0uwhy, todavía no los datos binarios originales y no una imagen válida =(
    • href=»http://imgur.com/1LHya» >imgur.com/1LHya S, mi mal! En el servidor, debe dividir la cadena base64 por «,» y sólo en el almacén de la segunda parte – así que tipo de mime no se almacenan con real contenido del archivo.
    • Es eficiente para hacerlo?
    • no, no es eficiente. esto aumentará el tamaño del archivo 137% y hacer que la sobrecarga del servidor. pero no hay otra manera de apoyar a F*** IE
    • Si usted tiene PHP? Estás seguro? Es realmente fácil de decodificación base64 así que tu comentario es inexacta.
    • funcionó a la perfección, gracias!

  2. 101

    (Siguiente es una tarde, pero la respuesta completa)

    FileReader métodos de apoyo


    FileReader.readAsBinaryString() es en desuso. No lo use! Ya no está en el API de Archivo del W3C borrador de trabajo:

    void abort();
    void readAsArrayBuffer(Blob blob);
    void readAsText(Blob blob, optional DOMString encoding);
    void readAsDataURL(Blob blob);

    NOTA: tenga en cuenta que File es una especie de prolongación de Blob estructura.

    Mozilla todavía implementa readAsBinaryString() y se describe en MDN FileApi documentación:

    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 readAsBinaryString() en desuso en mi opinión es la siguiente: el estándar de JavaScript son las cadenas de caracteres DOMString solo acepta caracteres UTF-8, NO al azar de datos binarios. Así que no lo use readAsBinaryString(), que no es seguro y ECMAScript conformes a todos.

    Sabemos que JavaScript cadenas no se supone que para almacenar datos binarios pero Mozilla en algún tipo puede. Eso es peligroso, en mi opinión. Blob y typed arrays (ArrayBuffer y de la que aún no se ha implementado, pero no es necesario StringView) fueron inventados para un propósito: permitir el uso de pura datos binarios sin formato UTF-8 cadenas de restricciones.

    XMLHttpRequest soporte de carga


    XMLHttpRequest.send() tiene las siguientes invocaciones opciones:

    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 invocaciones opciones:

    void sendAsBinary(   in DOMString body );

    sendAsBinary() NO es un estándar y puede no ser compatible en Chrome.

    Soluciones


    Así que tienes varias opciones:

    1. send() la FileReader.result de FileReader.readAsArrayBuffer ( fileObject ). Es más complicado de manipular (usted tendrá que hacer un aparte enviar() para ello) pero es la ENFOQUE RECOMENDADO.
    2. send() la FileReader.result de FileReader.readAsDataURL( fileObject ). Genera inútil la sobrecarga y la compresión de latencia, requiere de una descompresión de paso en el lado del servidor, PERO es fácil de manipular como una cadena en Javascript.
    3. No-estándar y sendAsBinary() la FileReader.result de FileReader.readAsBinaryString( fileObject )

    MDN establece que:

    La mejor manera de enviar contenido binario (como en los archivos de carga) es el uso de
    ArrayBuffers o manchas en conjuncton con el método send (). Sin embargo,
    si desea enviar un stringifiable los datos en bruto, el uso de la sendAsBinary()
    método en su lugar, o el StringView (No nativa) matrices de la superclase.

    • Me siento a cavar de nuevo, esto, sólo quería añadir que, probablemente, la forma más fácil para enviar datos binarios (etc. un archivo en PDF) es a través de FileReader.readAsDataURL y en onload controlador en lugar de simplemente enviar el event.target.result (que no es un lugar limpio codificado en base64 cadena) limpia primero con algunos regex como event.target.result = event.target.result.match(/,(.*)$/)[1] y enviar el real base64 a un servidor para ser decodificados.
    • Ya que cualquiera puede editar MDN, probablemente yo no lo uso como una fuente.
    • Eres mi héroe!
    • mejor uso event.target.result.split(",", 2)[1], no match.
    • En la opción recomendada, se menciona la necesidad de hacer un aparte enviar(). Por qué?
    • El enfoque recomendado trabajado para cargar un archivo adjunto utilizando TFS API de REST. Thx!

  3. 20

    La mejor manera en los navegadores que lo soportan, es enviar el archivo como un Blob, o el uso de FormData si desea un formulario multipart. Usted no necesita un FileReader para que. Esto es tanto más simple y más eficiente que intentar leer los datos.

    Si usted desea específicamente para enviarlo como multipart/form-data, puede utilizar 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);

    Usted también puede enviar los datos directamente, en lugar de utilizar multipart/form-data. Ver el documentación. Por supuesto, esto tendrá un servidor del lado del cambio.

    //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 el soporte de los navegadores, consulte: http://caniuse.com/#feat=xhr2 (la mayoría de los navegadores, incluyendo IE 10+).

    • xmlHttpRequest.enviar(formData);
    • gracias, corregido.
    • Por último, una adecuada respuesta también sin el uso de FormData. Parece que todo el mundo es el uso de un formulario, mientras que todo lo que necesitas es subir un solo archivo… Gracias!
    • Estuve buscando durante horas cómo conseguir que esta trabajando para un archivo mp3 de carga a través de ajax, esto hace el truco!
    • Una cosa que creo que usted no necesita hacer setRequestHeader ya que será automática mediante el envío de formData y se verá algo como esto «Content-Type: multipart/form-data; boundary=—-WebKitFormBoundaryQA8d7glpaso6zKsa» En mi caso se rompió CORS a menos que me quita setRequestHeader.
    • Nota: Mi comentario anterior sólo se aplica cuando se utiliza objeto formData.

Dejar respuesta

Please enter your comment!
Please enter your name here