[ Web Proxy ]
URL:
Viewing: https://developer.mozilla.org/es/docs/Web/API/XMLHttpRequest_API/Using_XMLHttpRequest [Back]  [Original]

Utilizando XMLHttpRequest - API web | MDN

Esta pgina ha sido traducida del ingls por la comunidad. Aprende ms y nete a la comunidad de MDN Web Docs.

View in English Always switch to English

Utilizando XMLHttpRequest

Baseline Widely available *

This feature is well established and works across many devices and browser versions. Its been available across browsers since julio de 2015.

* Some parts of this feature may have varying levels of support.

En esta gua le echaremos un vistazo a cmo usar XMLHttpRequest para enviar solicitudes HTTP con el objetivo de intercambiar datos entre el sitio web y el servidor.

Se incluyen ejemplos, tanto para los casos de uso comunes de XMLHttpRequest, como para los ms inusuales.

Para enviar una solicitud HTTP, cree un objeto XMLHttpRequest, abra una URL y enve la solicitud. Una vez que la transaccin haya sido completada, el objeto contendr informacin til tal como el cuerpo de la respuesta y el estado HTTP status del resultado.

js
function reqListener() {
  console.log(this.responseText);
}

var oReq = new XMLHttpRequest();
oReq.addEventListener("load", reqListener);
oReq.open("GET", "http://www.example.org/example.txt");
oReq.send();

In this article

Tipos de peticiones

Una peticin realizada a travs de XMLHttpRequest puede obtener los datos de una estas dos maneras, de forma asncrona o sincrnica. El tipo de peticin viene dictado por el argumento opcional async (el tercer argumento) que se establece en el mtodo XMLHttpRequest.open(). Si este argumento es true o no se especifica, la XMLHttpRequest se procesa de forma asncrona, de lo contrario el proceso se realiza de forma sncrona. Una discusin detallada y demostraciones de estos de estos dos tipos de peticiones en la pgina peticiones sncronas y asncronas. No utilice solicitudes sincrnicas fuera de los Web Workers.

Nota: A partir de Gecko 30.0 (Firefox 30.0 / Thunderbird 30.0 / SeaMonkey 2.27), las peticiones sncronas en el hilo principal han sido marcadas como obsoletas debido a los efectos negativos en la experiencia del usuario.

Nota: La funcin constructora XMLHttpRequest no se limita a los documentos XML. Comienza con "XML" porque cuando se cre el formato principal que se utilizaba originalmente para el intercambio de datos asncrono era XML.

Manejando las respuestas

Hay varios tipos de atributos de respuesta definidos por la especificacin del estndar para el constructor XMLHttpRequest(). Esto le dice al cliente que realiza el XMLHttpRequest informacin importante sobre el estado de la respuesta. Algunos casos en los que tratar con tipos de respuesta no textuales puede implicar alguna manipulacin y anlisis como se describen en las siguientes secciones.

Analizar y manipular la propiedad responseXML

Si utiliza XMLHttpRequest para obtener el contenido de un documento XML remoto, la propiedad responseXML ser un objeto DOM que contiene un documento XML analizado. Esto podra resultar difcil de manipular y analizar. Principalmente hay cuatro formas de analizar este documento XML:

  1. Usando XPath para dirigir (o apuntar a) partes del mismo.
  2. Manualmente Analizar y serializar el XML a cadenas u objetos.
  3. Usando XMLSerializer para serializar rboles DOM a cadenas o a archivos.
  4. RegExp se puede utilizar si siempre se conoce el contenido del documento XML de antemano. Es posible que desee eliminar los saltos de lnea, si utiliza RegExp para escanear en lo que respecta a los saltos de lnea. Sin embargo, este mtodo es un "ltimo recurso" ya que si el cdigo XML cambia ligeramente, el mtodo probablemente fallar.

Nota: XMLHttpRequest ahora puede interpretar HTML por ti utilizando la propiedad responseXML. Lea el artculo sobre HTML en XMLHttpRequest para aprender como hacerlo.

Procesamiento de una propiedad responseText que contiene un documento HTML

Si usas XMLHttpRequest para obtener el contenido de una pgina web HTML remota, la propiedad responseText es una cadena que contiene el HTML en bruto. Esto podra resultar difcil de manipular y analizar. Principalmente hay tres tres formas de analizar y parsear esta cadena de HTML en bruto:

  1. Utilizar la propiedad XMLHttpRequest.responseXML como se explica en el artculo HTML en XMLHttpRequest.
  2. Inyectar el contenido en el cuerpo de un fragmento de documento mediante fragment.body.innerHTML y recorrer el DOM del fragmento.
  3. RegExp puede utilizarse si siempre se conoce el contenido del HTML responseText de antemano. Es posible que desee eliminar los saltos de lnea, si utiliza RegExp para escanear en lo que respecta a los saltos de lnea. Sin embargo, este mtodo es un "ltimo recurso" ya que si el cdigo HTML cambia ligeramente, el mtodo probablemente fallar.

Manejo de datos binarios

Aunque XMLHttpRequest se utiliza normalmente para enviar y recibir datos textuales, puede utilizarse para enviar y recibir contenido binario. Existen varios mtodos probados para forzar a la respuesta de un XMLHttpRequest para que enve datos binarios. Se trata de utilizar la funcin overrideMimeType() en el objeto XMLHttpRequest y es una solucin viable.

js
var oReq = new XMLHttpRequest();
oReq.open("GET", url);
// recuperar los datos sin procesar como una cadena binaria
oReq.overrideMimeType("text/plain; charset=x-user-defined");
/* ... */

Sin embargo, existen tcnicas ms modernas, ya que el responseType admite ahora una serie de tipos de contenido adicionales, lo que facilita el envo y la recepcin de datos binarios.

Por ejemplo, considere este fragmento, que utiliza el responseType de "arraybuffer" para obtener el contenido remoto en un objeto ArrayBuffer que almacena los datos binarios en bruto.

js
var oReq = new XMLHttpRequest();

oReq.onload = function (e) {
  var arraybuffer = oReq.response; // no responseText
  /* ... */
};
oReq.open("GET", url);
oReq.responseType = "arraybuffer";
oReq.send();

Para ver ms ejemplos, consulte la pgina Envo y recepcin de datos binarios

Seguimiento del progreso

XMLHttpRequest proporciona la capacidad de escuchar varios eventos que pueden ocurrir mientras se procesa la solicitud. Esto incluye notificaciones peridicas del progreso, notificaciones de error, etc.

La implementacin para la monitorizacin de eventos DOM progress de transferencias XMLHttpRequest sigue la especificacin de eventos de progreso: estos eventos implementan la interfaz ProgressEvent. Los eventos reales que puedes monitorizar para determinar el estado de una transferencia en curso son:

progress

La cantidad de datos que se han recibido ha cambiado.

load

La transferencia se ha completado; todos los datos estn ahora en el response.

js
var oReq = new XMLHttpRequest();

oReq.addEventListener("progress", updateProgress);
oReq.addEventListener("load", transferComplete);
oReq.addEventListener("error", transferFailed);
oReq.addEventListener("abort", transferCanceled);

oReq.open();

// ...

// progreso de las transferencias del servidor al cliente (descargas)
function updateProgress(oEvent) {
  if (oEvent.lengthComputable) {
    var percentComplete = (oEvent.loaded / oEvent.total) * 100;
    // ...
  } else {
    // No se puede calcular la informacin de progreso ya que el tamao total es desconocido
  }
}

function transferComplete(evt) {
  console.log("La transferencia se ha completado.");
}

function transferFailed(evt) {
  console.log("Se ha producido un error al transferir el archivo.");
}

function transferCanceled(evt) {
  console.log("La transferencia ha sido cancelada por el usuario.");
}

Las lneas 3-6 aaden escuchadores de eventos para los distintos eventos que se envan al realizar una transferencia de datos utilizando XMLHttpRequest.

Nota: Tienes que aadir los escuchadores de eventos antes de llamar a open() en la peticin. De lo contrario, los eventos `progress no se dispararn.

El manejador de eventos de progreso, especificado por la funcin updateProgress() en este ejemplo, recibe el nmero total de bytes a transferir as como el nmero de bytes transferidos hasta el momento en los campos total y loaded del evento. Sin embargo, si el campo lengthComputable es falso, la longitud total no se conoce y ser cero.

Los eventos de progreso existen tanto para las transferencias de descarga como de subida. Los eventos de descarga se disparan en el propio objeto XMLHttpRequest, como se muestra en el ejemplo anterior. Los eventos de subida se disparan en el objeto XMLHttpRequest.upload, como se muestra a continuacin:

js
var oReq = new XMLHttpRequest();

oReq.upload.addEventListener("progress", updateProgress);
oReq.upload.addEventListener("load", transferComplete);
oReq.upload.addEventListener("error", transferFailed);
oReq.upload.addEventListener("abort", transferCanceled);

oReq.open();

Nota: Los eventos de progreso no estn disponibles para el protocolo file:.

Nota: A partir de Gecko 9.0, se puede confiar en que los eventos de progreso lleguen para cada trozo de datos recibidos, incluyendo el ltimo trozo en los casos en los que se recibe el ltimo paquete y se cierra la conexin antes de que se dispare el evento de progreso. En este caso, el evento de progreso se dispara automticamente cuando se produce el evento de carga para ese paquete. Esto te permite ahora monitorizar de forma fiable el progreso observando nicamente el evento "progress".

Nota: A partir de Gecko 12.0, si su evento de progreso es llamado con un responseType de "moz-blob", el valor de la respuesta es un Blob que contiene los datos recibidos hasta el momento.

Tambin se pueden detectar las tres condiciones de finalizacin de la carga (abort, load, o error) utilizando el evento loadend:

js
req.addEventListener("loadend", loadEnd);

function loadEnd(e) {
  console.log(
    "La transferencia ha terminado (aunque no sabemos si ha tenido xito o no).",
  );
}

Ten en cuenta que no hay forma de estar seguros, a partir de la informacin recibida por el evento de la informacin recibida por el evento loadend, en cuanto a la condicin que caus la terminacin de la operacin; sin embargo, puede utilizar esto para manejar las tareas que deben realizarse en todos los escenarios de fin de transferencia.

Envo de formularios y subida de archivos

Las instancias de XMLHttpRequest pueden utilizarse para enviar formularios de dos maneras:

  • usando slo AJAX
  • utilizando la API FormData

El uso de la API FormData es el ms sencillo y rpido, pero tiene la desventaja de que los datos recogidos no pueden ser stringificados.

Utilizar slo AJAX es ms complejo, pero suele ser ms flexible y potente.

Usando nada ms que XMLHttpRequest

El envo de formularios sin la API FormData no necesita de otras APIs para la mayora de los casos de uso. El nico caso en el que necesita una API adicional es si quiere subir uno o ms archivos, donde se utiliza la API FileReader.

Una breve introduccin a los mtodos de envo

Un html <form> puede ser enviado de cuatro maneras:

  • utilizando el mtodo POST y estableciendo el atributo enctype a application/x-www-form-urlencoded (por defecto);
  • utilizando el mtodo POST y estableciendo el atributo enctype como text/plain;
  • utilizando el mtodo POST y estableciendo el atributo enctype como multipart/form-data;
  • utilizando el mtodo GET (en este caso el atributo enctype se ser ignorado).

Consideremos ahora el envo de un formulario que contiene slo dos campos, llamados foo y baz. Si est utilizando el mtodo POST el servidor recibir una cadena similar a uno de los tres ejemplos siguientes, dependiendo dependiendo del tipo de codificacin que est utilizando:

  • Mtodo: POST; Tipo de codificacin: application/x-www-form-urlencoded (por defecto):

    Content-Type: application/x-www-form-urlencoded
    
    foo=bar&baz=The+first+line.%0D%0AThe+second+line.%0D%0A
    
  • Mtodo: POST; Tipo de codificacin: text/plain:

    Content-Type: text/plain
    
    foo=bar
    baz=The first line.
    The second line.
    
  • Mtodo: POST; Tipo de codificacin: multipart/form-data:

    Content-Type: multipart/form-data; boundary=---------------------------314911788813839
    
    -----------------------------314911788813839
    Content-Disposition: form-data; name="foo"
    
    bar
    -----------------------------314911788813839
    Content-Disposition: form-data; name="baz"
    
    The first line.
    The second line.
    
    -----------------------------314911788813839--
    

Sin embargo, si utiliza el mtodo GET, se aadir a la URL una cadena como la siguiente:

?foo=bar&baz=The%20first%20line.%0AThe%20second%20line.

Un pequeo framework vanilla

Todos estos efectos son realizados automticamente por el navegador web cada vez que se enva un <form>. Si quieres realizar los mismos efectos usando JavaScript tiene que tiene que instruir al intrprete sobre todo. Por lo tanto, la forma de enviar formularios en puro AJAX es demasiado complejo para ser explicado aqu en detalle. Por esta razn, aqu colocamos un completo (aunque didctico) framework, capaz de utilizar las cuatro formas de enviar, y de subir archivos:

html
<!doctype html>
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <title>Envo de formularios con AJAX puro &ndash; MDN</title>
    <script type="text/javascript">
      "use strict";

      /*\
      |*|
      |*|  :: XMLHttpRequest.prototype.sendAsBinary() Polyfill ::
      |*|
      |*|  https://developer.mozilla.org/es/docs/DOM/XMLHttpRequest#sendAsBinary()
      \*/

      if (!XMLHttpRequest.prototype.sendAsBinary) {
        XMLHttpRequest.prototype.sendAsBinary = function (sData) {
          var nBytes = sData.length,
            ui8Data = new Uint8Array(nBytes);
          for (var nIdx = 0; nIdx < nBytes; nIdx++) {
            ui8Data[nIdx] = sData.charCodeAt(nIdx) & 0xff;
          }
          /* enviar como ArrayBufferView...: */
          this.send(ui8Data);
          /* ...o como ArrayBuffer (legacy)...: this.send(ui8Data.buffer); */
        };
      }

      /*\
      |*|
      |*|  :: AJAX Framework de envo de formulario ::
      |*|
      |*|  https://developer.mozilla.org/es/docs/DOM/XMLHttpRequest/Using_XMLHttpRequest
      |*|
      |*|  Este framework est publicado bajo la licencia pblica GNU, versin 3 o posterior.
      |*|  https://www.gnu.org/licenses/gpl-3.0-standalone.html
      |*|
      |*|  Sintaxis:
      |*|
      |*|   AJAXSubmit(HTMLFormElement);
      \*/

      var AJAXSubmit = (function () {
        function ajaxSuccess() {
          /* console.log("AJAXSubmit - xito!"); */
          console.log(this.responseText);
          /* puedes obtener los datos serializados a travs de la propiedad personalizada "submittedData": */
          /* console.log(JSON.stringify(this.submittedData)); */
        }

        function submitData(oData) {
          /* la peticin AJAX... */
          var oAjaxReq = new XMLHttpRequest();
          oAjaxReq.submittedData = oData;
          oAjaxReq.onload = ajaxSuccess;
          if (oData.technique === 0) {
            /* el mtodo es GET */
            oAjaxReq.open(
              "get",
              oData.receiver.replace(
                /(?:\?.*)?$/,
                oData.segments.length > 0 ? "?" + oData.segments.join("&") : "",
              ),
              true,
            );
            oAjaxReq.send(null);
          } else {
            /* el mtodo es POST */
            oAjaxReq.open("post", oData.receiver, true);
            if (oData.technique === 3) {
              /* enctype es multipart/form-data */
              var sBoundary =
                "---------------------------" + Date.now().toString(16);
              oAjaxReq.setRequestHeader(
                "Content-Type",
                "multipart\/form-data; boundary=" + sBoundary,
              );
              oAjaxReq.sendAsBinary(
                "--" +
                  sBoundary +
                  "\r\n" +
                  oData.segments.join("--" + sBoundary + "\r\n") +
                  "--" +
                  sBoundary +
                  "--\r\n",
              );
            } else {
              /* enctype es application/x-www-form-urlencoded or text/plain */
              oAjaxReq.setRequestHeader("Content-Type", oData.contentType);
              oAjaxReq.send(
                oData.segments.join(oData.technique === 2 ? "\r\n" : "&"),
              );
            }
          }
        }

        function processStatus(oData) {
          if (oData.status > 0) {
            return;
          }
          /* el formulario est ahora totalmente serializado! haz algo antes de enviarlo al servidor... */
          /* doSomething(oData); */
          /* console.log("AJAXSubmit - El formulario est ahora serializado. Enviando..."); */
          submitData(oData);
        }

        function pushSegment(oFREvt) {
          this.owner.segments[this.segmentIdx] += oFREvt.target.result + "\r\n";
          this.owner.status--;
          processStatus(this.owner);
        }

        function plainEscape(sText) {
          /* Cmo debo tratar la codificacin de un formulario text/plain?
       Qu caracteres no estn permitidos? Esto es lo que supongo..: */
          /* "4\3\7 - Einstein dijo E=mc2" ----> "4\\3\\7\ -\ Einstein\ dijo\ E\=mc2" */
          return sText.replace(/[\s\=\\]/g, "\\$&");
        }

        function SubmitRequest(oTarget) {
          var nFile,
            sFieldType,
            oField,
            oSegmReq,
            oFile,
            bIsPost = oTarget.method.toLowerCase() === "post";
          /* console.log("AJAXSubmit - Serializando formulario..."); */
          this.contentType =
            bIsPost && oTarget.enctype
              ? oTarget.enctype
              : "application\/x-www-form-urlencoded";
          this.technique = bIsPost
            ? this.contentType === "multipart\/form-data"
              ? 3
              : this.contentType === "text\/plain"
                ? 2
                : 1
            : 0;
          this.receiver = oTarget.action;
          this.status = 0;
          this.segments = [];
          var fFilter = this.technique === 2 ? plainEscape : escape;
          for (var nItem = 0; nItem < oTarget.elements.length; nItem++) {
            oField = oTarget.elements[nItem];
            if (!oField.hasAttribute("name")) {
              continue;
            }
            sFieldType =
              oField.nodeName.toUpperCase() === "INPUT" &&
              oField.hasAttribute("type")
                ? oField.getAttribute("type").toUpperCase()
                : "TEXT";
            if (sFieldType === "FILE" && oField.files.length > 0) {
              if (this.technique === 3) {
                /* enctype es multipart/form-data */
                for (nFile = 0; nFile < oField.files.length; nFile++) {
                  oFile = oField.files[nFile];
                  oSegmReq = new FileReader();
                  /* (propiedades personalizadas:) */
                  oSegmReq.segmentIdx = this.segments.length;
                  oSegmReq.owner = this;
                  /* (fin de las propiedades personalizadas) */
                  oSegmReq.onload = pushSegment;
                  this.segments.push(
                    'Content-Disposition: form-data; name="' +
                      oField.name +
                      '"; filename="' +
                      oFile.name +
                      '"\r\nContent-Type: ' +
                      oFile.type +
                      "\r\n\r\n",
                  );
                  this.status++;
                  oSegmReq.readAsBinaryString(oFile);
                }
              } else {
                /* enctype es application/x-www-form-urlencoded or text/plain or
             el mtodo es GET: los archivos no se enviarn! */
                for (
                  nFile = 0;
                  nFile < oField.files.length;
                  this.segments.push(
                    fFilter(oField.name) +
                      "=" +
                      fFilter(oField.files[nFile++].name),
                  )
                );
              }
            } else if (
              (sFieldType !== "RADIO" && sFieldType !== "CHECKBOX") ||
              oField.checked
            ) {
              /* NOTA: esto enviar _todos_ los botones de envo. Detectar el correcto no es trivial. */
              /* el tipo de campo no es FILE o es FILE pero est vaco */
              this.segments.push(
                this.technique === 3 /* enctype es multipart/form-data */
                  ? 'Content-Disposition: form-data; name="' +
                      oField.name +
                      '"\r\n\r\n' +
                      oField.value +
                      "\r\n"
                  : /* enctype es application/x-www-form-urlencoded o text/plain el mtodo es GET */
                    fFilter(oField.name) + "=" + fFilter(oField.value),
              );
            }
          }
          processStatus(this);
        }

        return function (oFormElement) {
          if (!oFormElement.action) {
            return;
          }
          new SubmitRequest(oFormElement);
        };
      })();
    </script>
  </head>
  <body>
    <h1>Envo de formularios con AJAX puro</h1>

    <h2>Utilizando el mtodo GET</h2>

    <form
      action="register.php"
      method="get"
      >
      <fieldset>
        <legend>Ejemplo de registro</legend>
        <p>
          Nombre: <input type="text" name="firstname" /><br />
          Apellido: <input type="text" name="lastname" />
        </p>
        <p>
          <input type="submit" value="Submit" />
        </p>
      </fieldset>
    </form>

    <h2>Utilizando el mtodo POST</h2>
    <h3>Enctype: application/x-www-form-urlencoded (por defecto)</h3>

    <form
      action="register.php"
      method="post"
      >
      <fieldset>
        <legend>Ejemplo de registro</legend>
        <p>
          Nombre: <input type="text" name="firstname" /><br />
          Apellido: <input type="text" name="lastname" />
        </p>
        <p>
          <input type="submit" value="Submit" />
        </p>
      </fieldset>
    </form>

    <h3>Enctype: text/plain</h3>

    <form
      action="register.php"
      method="post"
      enctype="text/plain"
      >
      <fieldset>
        <legend>Ejemplo de registro</legend>
        <p>Tu nombre: <input type="text" name="user" /></p>
        <p>
          Tu mensaje:<br />
          <textarea name="message" cols="40" rows="8"></textarea>
        </p>
        <p>
          <input type="submit" value="Submit" />
        </p>
      </fieldset>
    </form>

    <h3>Enctype: multipart/form-data</h3>

    <form
      action="register.php"
      method="post"
      enctype="multipart/form-data"
      >
      <fieldset>
        <legend>Ejemplo de subida</legend>
        <p>
          Nombre: <input type="text" name="firstname" /><br />
          Apellido: <input type="text" name="lastname" /><br />
          Sexo:
          <input id="sex_male" type="radio" name="sex" value="male" />
          <label for="sex_male">Hombre</label>
          <input id="sex_female" type="radio" name="sex" value="female" />
          <label for="sex_female">Mujer</label><br />
          Contrasea: <input type="password" name="secret" /><br />
          Qu prefieres?:
          <select name="image_type">
            <option>Libros</option>
            <option>Cine</option>
            <option>TV</option>
          </select>
        </p>
        <p>
          Enva tus fotos:
          <input type="file" multiple name="photos[]" />
        </p>
        <p>
          <input
            id="vehicle_bike"
            type="checkbox"
            name="vehicle[]"
            value="Bike" />
          <label for="vehicle_bike">Tengo una bicicleta</label><br />
          <input
            id="vehicle_car"
            type="checkbox"
            name="vehicle[]"
            value="Car" />
          <label for="vehicle_car">Tengo un coche</label>
        </p>
        <p>
          Descrbete:<br />
          <textarea name="description" cols="50" rows="8"></textarea>
        </p>
        <p>
          <input type="submit" value="Submit" />
        </p>
      </fieldset>
    </form>
  </body>
</html>

Para probar esto, cree una pgina llamada register.php (que es la que se encuentra en el atributo action de estos formularios de muestra), y ponga lo siguiente contenido minimalista:

php
<?php
/* register.php */

header("Content-type: text/plain");

/*
NOTA: Nunca debe usar `print_r()` en scripts de produccin, o
o datos enviados por el cliente sin sanearlos antes.
No sanearlos puede llevar a vulnerabilidades tipo _cross-site scripting_.
*/

echo ":: Datos recibidos a travs de GET ::\n\n";
print_r($_GET);

echo "\n\n:: Datos recibidos a travs de POST ::\n\n";
print_r($_POST);

echo "\n\n:: Datos recibidos \"sin procesar\" (text/plain encoding) ::\n\n";
if (isset($HTTP_RAW_POST_DATA)) { echo $HTTP_RAW_POST_DATA; }

echo "\n\n:: Archivos recibidos ::\n\n";
print_r($_FILES);

La sintaxis para activar este script es:

js
AJAXSubmit(myForm);

Nota: Este framework utiliza la API FileReader para transmitir las cargas de archivos. Este es un API reciente y no est implementada en IE9 o inferiores. Por esta razn, la carga slo en AJAX se considera una tcnica experimental. Si no necesita subir archivos binarios, este framework funciona bien en la mayora de los navegadores.

Nota: La mejor manera de enviar contenido binario es a travs de ArrayBuffers o Blobs junto con con el mtodo send() y posiblemente el mtodo readAsArrayBuffer() de la API FileReader. Pero, como el objetivo de este script es trabajar con un stringifiable de datos en bruto, utilizamos el mtodo sendAsBinary() junto con el mtodo readAsBinaryString() de la API FileReader. Por lo tanto, el script anterior tiene sentido slo cuando se trata de archivos pequeos. Si no tiene intencin de de cargar contenido binario, considere utilizar la API FormData.

Nota: El mtodo no estndar sendAsBinary se considera obsoleto a partir de Gecko 31 (Firefox 31 / Thunderbird 31 / SeaMonkey 2.28) y se eliminar pronto. En su lugar se puede utilizar el mtodo estndar send(Blob data).

Uso de los objetos FormData

El constructor FormData permite recopilar un conjunto de pares clave/valor para enviarlos mediante XMLHttpRequest. Su uso principal es para enviar datos de formularios, pero tambin puede utilizarse independientemente de un formulario para transmitir datos clave del usuario. Los datos transmitidos tienen el mismo formato que el mtodo del formulario para enviar los datos, si el tipo de codificacin del formulario se establece como "multipart/form-data". Los objetos FormData pueden utilizarse de varias maneras con un mtodo XMLHttpRequest. Para ver ejemplos y explicaciones de cmo se puede utilizar FormData con XMLHttpRequests, consulte la seccin Utilizando objetos FormData. Para fines didcticos aqu hay una traduccin del ejemplo anterior transformado para usar la API FormData. Ntese la brevedad del cdigo:

html
<!doctype html>
<html>
  <head>
    <meta http-equiv="Content-Type" charset="UTF-8" />
    <title>Envo de formularios con FormData &ndash; MDN</title>
    <script>
      "use strict";

      function ajaxSuccess() {
        console.log(this.responseText);
      }

      function AJAXSubmit(oFormElement) {
        if (!oFormElement.action) {
          return;
        }
        var oReq = new XMLHttpRequest();
        oReq.onload = ajaxSuccess;
        if (oFormElement.method.toLowerCase() === "post") {
          oReq.open("post", oFormElement.action);
          oReq.send(new FormData(oFormElement));
        } else {
          var oField,
            sFieldType,
            nFile,
            sSearch = "";
          for (var nItem = 0; nItem < oFormElement.elements.length; nItem++) {
            oField = oFormElement.elements[nItem];
            if (!oField.hasAttribute("name")) {
              continue;
            }
            sFieldType =
              oField.nodeName.toUpperCase() === "INPUT" &&
              oField.hasAttribute("type")
                ? oField.getAttribute("type").toUpperCase()
                : "TEXT";
            if (sFieldType === "FILE") {
              for (
                nFile = 0;
                nFile < oField.files.length;
                sSearch +=
                  "&" +
                  escape(oField.name) +
                  "=" +
                  escape(oField.files[nFile++].name)
              );
            } else if (
              (sFieldType !== "RADIO" && sFieldType !== "CHECKBOX") ||
              oField.checked
            ) {
              sSearch += "&" + escape(oField.name) + "=" + escape(oField.value);
            }
          }
          oReq.open(
            "get",
            oFormElement.action.replace(
              /(?:\?.*)?$/,
              sSearch.replace(/^&/, "?"),
            ),
            true,
          );
          oReq.send(null);
        }
      }
    </script>
  </head>
  <body>
    <h1>Envo de formularios con FormData</h1>

    <h2>Utilizando el mtodo GET</h2>

    <form
      action="register.php"
      method="get"
      >
      <fieldset>
        <legend>Ejemplo de registro</legend>
        <p>
          Nombre: <input type="text" name="firstname" /><br />
          Apellido: <input type="text" name="lastname" />
        </p>
        <p>
          <input type="submit" value="Submit" />
        </p>
      </fieldset>
    </form>

    <h2>Utilizando el mtodo POST</h2>
    <h3>Enctype: application/x-www-form-urlencoded (por defecto)</h3>

    <form
      action="register.php"
      method="post"
      >
      <fieldset>
        <legend>Ejemplo de registro</legend>
        <p>
          Nombre: <input type="text" name="firstname" /><br />
          Apellido: <input type="text" name="lastname" />
        </p>
        <p>
          <input type="submit" value="Submit" />
        </p>
      </fieldset>
    </form>

    <h3>Enctype: text/plain</h3>

    <p>La codificacin text/plain no est permitida en la API de FormData.</p>

    <h3>Enctype: multipart/form-data</h3>

    <form
      action="register.php"
      method="post"
      enctype="multipart/form-data"
      >
      <fieldset>
        <legend>Ejemplo de subida</legend>
        <p>
          Nombre: <input type="text" name="firstname" /><br />
          Apellido: <input type="text" name="lastname" /><br />
          Sexo:
          <input id="sex_male" type="radio" name="sex" value="male" />
          <label for="sex_male">Hombre</label>
          <input id="sex_female" type="radio" name="sex" value="female" />
          <label for="sex_female">Mujer</label><br />
          Contrasea: <input type="password" name="secret" /><br />
          Qu prefieres?:
          <select name="image_type">
            <option>Libros</option>
            <option>Cine</option>
            <option>TV</option>
          </select>
        </p>
        <p>
          Enva tus fotos:
          <input type="file" multiple name="photos[]" />
        </p>
        <p>
          <input
            id="vehicle_bike"
            type="checkbox"
            name="vehicle[]"
            value="Bike" />
          <label for="vehicle_bike">Tengo una bicicleta</label><br />
          <input
            id="vehicle_car"
            type="checkbox"
            name="vehicle[]"
            value="Car" />
          <label for="vehicle_car">Tengo un coche</label>
        </p>
        <p>
          Descrbete:<br />
          <textarea name="description" cols="50" rows="8"></textarea>
        </p>
        <p>
          <input type="submit" value="Submit" />
        </p>
      </fieldset>
    </form>
  </body>
</html>

Nota: Como hemos dicho, los objetos FormData no son objetos stringifiable. Si quieres transformar en string los datos enviados, utiliza el ejemplo anterior en puro-AJAX. Tenga en cuenta tambin que, aunque en este ejemplo hay algunos campos file <input>, cuando se enva un formulario a travs de la API FormData tampoco es necesario utilizar la API FileReader: los archivos se cargan y suben automticamente.

Obtener la fecha de la ltima modificacin

js
function getHeaderTime() {
  console.log(
    this.getResponseHeader("Last-Modified"),
  ); /* Una fecha GMTString vlida o null */
}

var oReq = new XMLHttpRequest();
oReq.open(
  "HEAD" /* utiliza HEAD si slo necesitas las cabeceras! */,
  "yourpage.html",
);
oReq.onload = getHeaderTime;
oReq.send();

Hacer algo cuando cambia la ltima fecha de modificacin

Vamos a crear dos funciones:

js
function getHeaderTime() {
  var nLastVisit = parseFloat(
    window.localStorage.getItem("lm_" + this.filepath),
  );
  var nLastModified = Date.parse(this.getResponseHeader("Last-Modified"));

  if (isNaN(nLastVisit) || nLastModified > nLastVisit) {
    window.localStorage.setItem("lm_" + this.filepath, Date.now());
    isFinite(nLastVisit) && this.callback(nLastModified, nLastVisit);
  }
}

function ifHasChanged(sURL, fCallback) {
  var oReq = new XMLHttpRequest();
  oReq.open(
    "HEAD" /* utiliza HEAD - slo necesitamos las cabeceras! */,
    sURL,
  );
  oReq.callback = fCallback;
  oReq.filepath = sURL;
  oReq.onload = getHeaderTime;
  oReq.send();
}

Y para probar:

js
/* Probemos el fichero "yourpage.html"... */

ifHasChanged("yourpage.html", function (nModified, nVisit) {
  console.log(
    "La pgina '" +
      this.filepath +
      "' ha cambiado el " +
      new Date(nModified).toLocaleString() +
      "!",
  );
});

Si quieres saber si la pgina actual ha cambiado, por favor, lee el artculo sobre document.lastModified.

Cross-site XMLHttpRequest

Los navegadores modernos admiten las peticiones cross-site implementando el estndar Recursos compartidos de origen-cruzado (CORS). Siempre que el servidor est configurado para permitir las peticiones desde el origen de su aplicacin web, XMLHttpRequest funcionar. En caso contrario, se lanzar una excepcin INVALID_ACCESS_ERR.

Evitar la cach

Un enfoque compatible con todos los navegadores para evitar la cach es aadir una marca de tiempo a a la URL, asegurndose de incluir un "?" o "&" segn corresponda. Por ejemplo:

http://foo.com/bar.html -> http://foo.com/bar.html?12345
http://foo.com/bar.html?foobar=baz -> http://foo.com/bar.html?foobar=baz&12345

Como la cach local se indexa por URL, esto hace que cada peticin sea nica, por lo que salta la cach.

Puedes ajustar automticamente las URLs usando el siguiente cdigo:

js
var oReq = new XMLHttpRequest();

oReq.open("GET", url + (/\?/.test(url) ? "&" : "?") + new Date().getTime());
oReq.send(null);

Seguridad

La manera recomendada para habilitar el cross-site scripting es utilizar la cabecera cabecera HTTP Access-Control-Allow-Origin en la respuesta al XMLHttpRequest.

XMLHttpRequests que se detienen

Si concluye con una XMLHttpRequest que recibe status=0 y statusText=null, significa que no se ha permitido realizar la peticin. Era UNSENT. Una causa probable de esto es cuando el origen XMLHttpRequest (en la creacin de la XMLHttpRequest) ha cambiado cuando el XMLHttpRequest es posterior a open(). Este caso puede darse, por ejemplo, cuando se tiene un XMLHttpRequest que se dispara en un evento onunload para una ventana, el esperado XMLHttpRequest se crea cuando la ventana a cerrar sigue ah, y finalmente enviar la peticin (en otras palabras, open()) cuando esta ventana ha perdido su foco y otra ventana toma el foco. La forma ms eficaz de evitar este problema es es establecer una escucha en el evento activate de la nueva ventana que se activa una vez que la ventana terminada tenga su evento unload disparado.

Workers

Establecer overrideMimeType no funciona desde un Worker. Ver Error 678057 en Firefox para ms detalles. Otros navegadores pueden manejar esto de manera diferente.

Especificaciones

Specification
XMLHttpRequest
# interface-xmlhttprequest

Compatibilidad con navegadores

Vase tambin

  1. MDN introduccin a AJAX
  2. HTML en XMLHttpRequest
  3. Control de acceso HTTP
  4. XMLHttpRequest - REST y la experiencia de usuario enriquecida
  5. Documentacin de Microsoft
  6. "Uso del objeto XMLHttpRequest" (jibbering.com)
  7. El objeto XMLHttpRequest: Especificacin WHATWG

Web Proxy Viewer  |  New URL  |  Original Page