Disectando XMLHttpRequest

Intro

Hace mucho, mucho tiempo atrás, comenté sobre los diversos métodos para recoger información desde el servidor sin recargar la página. Ocupé el término RPC vía HTTP para dar cuenta de este fenómeno, pero desde el artículo de Adaptative Path llamado ajax: a new approach to web applications, el nombre Ajax se ha incrustado en el inconsciente colectivo de todos nosotros.

Como bien dice nuestro estimado James, Ajax es un enfoque, más que una tecnología específica, que tiene como antecedente trucos tan sucios como recoger información en iframes escondidos, tal como lo hace mi querido jsrs. Ok, ok, hasta ahora no estoy diciendo nada que no haya dicho, pero sirve de introducción

Breve explicación de como funciona HTTP

Recordemos, ante que nada, que la WWW funciona con un modelo de cliente-servidor, siendo el cliente el navegador (Firefox, Mozilla, Opera o el engendro) y el servidor un demonio http (Apache, Zeus y el otro engendro).

En una carga de página normal, el cliente envía lo que se llama una petición al servidor. Cuando ponemos en la barra del navegador "http://php.apsique.com", enviamos el siguiente texto al servidor por un puerto, que generalmente es el 80:

GET   /	HTTP/1.0

Como vemos en la especificación del protocolo HTTP, existen diversos métodos a través de los cuales podemos decir al servidor que tipo de petición debemos hacer. Tenemos los clásicos GET Y POST, pero también otros como HEAD, DELETE y PUT. Lo importante es recordar que GET sirve para recuperar información sin alterar la fuente, en tanto que POST nos permite entregar información que altera el recurso.

El servidor, al recibir una petición, nos entrega una respuesta, que es también un texto. Esta respuesta siempre comienza con un código, que indica el estado de la operación. Entre ellos tenemos el esperado 200 (todo ok), 301 (movido permanentemente) y los temidos 403 (prohibido), 404 (no existe recurso) y 500 (error del cgi). Después de esta respuesta, generalmente se ofrece el tipo MIME del contenido (texto, xml, imagen) y el contenido propiamente tal. Por ejemplo, para una página típica de mi sitio

Date: Mon, 30 May 2005 07:12:49 GMT
Server: Apache/1.3.33 (Unix)  (Gentoo/Linux) mod_ruby/1.2.4 Ruby/1.8.2(2004-12-25) PHP/4.3.11
X-Powered-By: PHP/4.3.11
Keep-Alive: timeout=15, max=100
Connection: Keep-Alive
Transfer-Encoding: chunked
Content-Type: text/html; charset=utf-8

200 OK

A estas alturas del partido, si no han abandonado, se preguntarán porque les estoy dando tanto la lata. La respuesta es simple: si bien en una carga de página normal todo este enredo lo manejan de forma casi mágica el cliente y el servidor de forma automática, al ocupar Ajax hay que manejar todo esto, en el fondo, a mano. Si bien ya existen bastantes aplicaciones que ocultan esta información, si no tienen claro el proceso de consulta y respuesta, no van a poder entender bien como funciona el proceso en realidad y de donde surgen los errores.

Ajax

Ya teniendo en nuestras cabezas el proceso de consulta-respuesta, podemos empezar a trabajar en Ajax. Si quieren un texto muy bueno, y en el cual se basará la discusión, lean Using the XML HTTP Request object

El nombre Ajax es un acrónimo de "Asynchronous JavaScript + XML". Ahora, no es necesario ocupar XML. Si, tal como lo oyeron. Si bien siempre suena bonito ocupar esta siglita, la verdad es que la consulta y recepción son simples textos; así, si bien se puede ocupar XML para ordenar la cosa, no estamos limitados por ello.

Javascript al mando

A partir del Explorer 6 (si no me equivoco) y de Mozilla 1.6, tenemos a nuestra disposición el objeto XMLHttpRequest. El problemita es que en IE (para variar) se accede a el con

new ActiveXObject("Msxml2.XMLHTTP")
o
new ActiveXObject("Microsoft.XMLHTTP")
dependiendo de la versión del IE. Por tanto, lo mejor es crear una función que nos entregue el objeto, la cual diría algo como:
  1.  function get_xmlhttp() {
  2.  try {
  3.   xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
  4.   } catch (e) {
  5.   try {
  6.   xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
  7.   } catch (E) {
  8.   xmlhttp = false;
  9.   }
  10.   }
  11.  if (!xmlhttp && typeof XMLHttpRequest!='undefined') {
  12.   xmlhttp = new XMLHttpRequest();
  13.  }
  14.  return xmlhttp
  15.  }

Una vez que tenemos el objeto, para hacer una petición debemos abrir la conexión y enviar la consulta. Para ello utilizados

  1.  xmlhttp.open(metodo, url,async);
  2.  xmlhttp.send(contenido);

Recuerden que si utilizamos "GET", bastará con poner las variables en el url, en el clásico formato

script.php?variable1=valor1&variable2=valor2

Escapando los carácteres extraños con encodeURIComponent. Si ocupan POST, deben enviar el contenido en la variable contenido en send, aunque por ahora no sé muy bien como se hace (apenas tenga el dato, aviso)

Normalmente, nosotros deseamos saber en que momento el servidor nos entrega la respuesta y realizar una función con ésta. Para ello, existe una función de xmlhttp llamada onreadystatechange, la cual se ejecuta cada vez que cambia el estado de la conexión. Sabiendo que la propiedad readyState se pone a 4 cuando la respuesta ha sido recibida, podemos mejorar el código haciendo

  1.  xmlhttp.open(metodo, url,async);
  2.   xmlhttp.onreadystatechange=function() {
  3.   if (xmlhttp.readyState==4) {
  4.   callback(xmlhttp)
  5.   }
  6.   }
  7.   xmlhttp.send(null)

callback es el nombre de una función que recibirá el resultado de la llamada al servidor

Si revisamos el objeto xmlhttp una vez recibida la respuesta, veremos que cuenta con los siguientes métodos de interés

getAllResponseHeaders()
Nos entrega todas las cabeceras de respuesta desde el servidor
status
El código de estatus de la petición (normalmente, 200)
responseText
Texto literal de la respuesta
responseXML
Objeto XMLDocument, el cual se puede analizar con las funciones de DOM típicas, como getElementById y similares.De aquí la X de Ajax

El servidor

Desde el lado del servidor, la cosa es muy sencilla. Podemos enviar las cabeceras que queramos, así como el texto que se nos antoje. Por ejemplo, podemos utilizar el código 304 para decir que la página no ha tenido actualización desde la última vez que se visitó

Un dato importante es que solamente si definimos el tipo de contenido como xml con

Content-type: text/xml

La propiedad responseXML tendrá un valor en el objeto xmlhttp

Ejemplo

Esa sería la teoría del asunto, mis estimados. Ahora, nada mejor que un buen ejemplo para que vean el bicho en operaciones. Como siempre, pueden encontrar los archivos como adjunto al final del post

Texto: XML:

Estatus

Nada por ahora

Cabecera

Nada por ahora

Cuerpo

Nada por ahora

Propiedades y métodos objeto xmlhttprequest

Nada por ahora
AdjuntoTamaño
xhttprequest.zip1.55 KB
Imagen de Francotirador

Por cierto - y no es que pretenda autopromocionarme - ¿leíste el artículo sobre Ajax que escribí hace un tiempo?...

http://www.mouse.cl/2005/rep/04/15/index.asp

Quizá sirva para quienes no se han interiorizado en el tema ;)

¡Salute!

Enviado por Francotirador el Lun, 30/05/2005 - 15:53.
Imagen de clbustos

Simpático artículo, mi estimado. Gracias por el link :)
Por lo menos desde mi óptica, trabajar en Ajax, en HTTP-RPC o como quieran llamarlo no es tan complicado, si sabes lo que estás haciendo. Claro, hay que saber un poco más de lo requerido para trabajar con un sistema clásico de cgi, pero el esfuerzo vale la pena.
Y a todo esto, feliz cumpleaños. Podrías ponerte un avatar, para identificarte rápido...

Enviado por clbustos el Lun, 30/05/2005 - 16:00.
Imagen de clbustos

Estimados:
Si han ocupado IE para ver el ejemplo de este artículo, les lanzará un error de javascript. El error fue olvidarme de poner "var" para "valor" y "xml" al buscar los valores de los input. En firefox funciona sin problemas. Mil perdones.
En la noche espero tener corregido el error, que de verdad es mínimo. Por ahora, el zip con los archivos para probar en el servidor de cada cual está corregido.
Actualización:Acabo de llegar y corregí el error. Debería funcionar en el engendro.

Enviado por clbustos el Lun, 30/05/2005 - 16:33.
Imagen de Php y otras yerbas, por Clbustos (trackback)

Objetivo
Al finalizar este artículo, el lector, si ha entendido algo, será capaz de

  • Entender de forma bastante vaga que son las codificaciones de caracteres
  • Decir, ¡A,ha!, cuando lea ASCII, ISO-8859-1, Unicode y UTF-8
Enviado por Php y otras yerbas, por Clbustos (trackback) (no verificado) el Jue, 09/06/2005 - 17:45.
Imagen de clbustos

Ok, ok, me equivoqué. No se debe ocupar escape para enviar las variables, sino encodeURLComponent. Hay que ver como funciona en IE.

Enviado por clbustos el Vie, 10/06/2005 - 00:09.
icono de usuario

Lei el comentario y me parece algo excelente que alguien se preocuope por subir estos comentarios a la red, ya que los que empezamos a programar con estas tecnologias nos damos una idea mas amplia de realizar nuestros trabajos de una manera eficiente.

Gracias

Enviado por juliocesar (no verificado) el Lun, 22/08/2005 - 11:22.
icono de usuario

He probado el objeto ajax, pero la unica falla k le encontre fue k no me deja mandar archivos en un formulario, es con lo unico k he tenido problemas, pero el resto de cosas, la raja. Si alguien ha intentado mandar archivos y le resulto por favor avise.

Enviado por BlackCat (no verificado) el Lun, 27/11/2006 - 10:42.
icono de usuario

Mil gracias por tu articulo, la verdad es que me he leido como 20.. en un ratito, me has sacado de sendos apuros.

Tienes una forma muy peculiar de explicar las cosas tks ^^

Enviado por Silvanha (no verificado) el Sáb, 14/06/2008 - 20:18.
Imagen de clbustos

De nada.
Mientras más me explico, más me complico.

Enviado por clbustos el Lun, 16/06/2008 - 10:17.

Enviar un comentario nuevo

El contenido de este campo se mantiene como privado y no se muestra públicamente.
  • Allowed HTML tags: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd>
  • Saltos automáticos de líneas y de párrafos.

Más información sobre opciones de formato