AJAX a pelo: XMLHttpRequest

En mi anterior artículo Pero qué xxxxxx es AJAX!!!!!??????, os introducía al mundo de AJAX y sus Frameworks para .NET. Sin embargo, a mí siempre me ha gustado conocer el fondo de las cosas, por lo que no me vale saber que dicho Framework funciona y ya está.

En la parte final de todo Framework AJAX, nos encontramos con XMLHttpRequest, con el que podemos enviar y recibir información de cliente a servidor sin recargar la página.

Cabe aclarar que nos vamos a mover en el mundo de javascript, todo lo haremos desde ahí en la parte del cliente, y en la parte del servidor podemos utilizar ASP.NET o cualquier otra tecnología web.

Lo curioso de todo es que usar AJAX a pelo con XMLHttpRequest es en realidad muy sencillo. Nosotros lo vamos a organizar en cuatro fases:

1.- Crear el objeto XMLHttpRequest
2.- Enviar la información
3.- Tratar la información en servidor
4.- Recoger la información en cliente

1.- Crear el objeto XMLHttpRequest
Como casi siempre en javascript, el XMLHttpRequest se obtiene de manera distinta para los distintos navegadores, pero el código más o menos "estándar" para estos quehaceres es:

var xmlHttp;
function CreateXmlHttp()
{
   
    // Probamos con IE
    try
    {
        // Funcionará para JavaScript 5.0
        xmlHttp = new ActiveXObject("Msxml2.XMLHTTP");
    }
    catch(e)
    {
        try
        {
            xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
        }
        catch(oc)
        {  
            xmlHttp = null;
        }
    }

    // Si no se trataba de un IE, probamos con esto
    if(!xmlHttp && typeof XMLHttpRequest != "undefined")
    {
        xmlHttp = new XMLHttpRequest();
    }

    return xmlHttp;
}


Donde vemos que primero probamos a crear el objeto para navegadores IE en su diferentes versiones, y si no es así (casi siempre FireFox) lo hacemos para el resto de navegadores. Hasta ahora todo muy sencillo.

2.- Enviar la información
Ahora lo que vamos a hacer es enviar la información del cliente a servidor:

function envioInfo(txt)
{
    // 1.- Creamos el objeto xmlHttpRequest
    CreateXmlHttp();
   
    // 2.- Definimos la llamada para hacer un simple GET.
    var ajaxRequest = 'receptor.aspx?Info=' + txt;

    // 3.- Marcar qué función manejará la respuesta
    xmlHttp.onreadystatechange = recogeInfo;
  
    // 4.- Enviar
    xmlHttp.open("GET", ajaxRequest, true);
    xmlHttp.send("");
}


Como vemos, lo que estamos haciendo es:
1.- Recoger la instancia del objeto XMLHttpRequest
2.- Asignar la URL donde mandaremos la petición y guardar en su QueryString la info que vamos a mandar
3.- Indicar qué función manejará la respuesta que nos devuelva el servidor (lo veremos más adelante)
4.- Enviamos la información. En nuestro ejemplo hacemos:

    xmlHttp.open("GET", ajaxRequest, true);

Lo que indica que utilizaremos el método GET, enviaremos la info a la url definida y sí queremos que se comporte de forma asíncrona (marcar false para exigir modo síncrono).

Posteriormente no tenemos más que mandar la petición con la función Send();

Sí, parece sencillo, pero hagamos dos observaciones importantes:

1º. Estamos utilizando el método GET, y uno de los aspectos a tener en cuenta es que si queremos enviar mucha información es posible que tengamos problemas. Por tanto, estaría bien poder hacer las peticiones vía post.
2º. Asynchronous JavaScript And XML... dónde está el XML aquí!!!??? En nuestro ejemplo mandábamos sólo ua poca info, pero si quisiéramos mandarle al servidor la discografía entera de los Beatles, tendríamos que pensar en la utilidad de XML como contenedor de información.

Veamos pues un ejemplo en el que se utiliza tanto el método POST como XML para mandar info.

function envioInfoPost(XML)
{
    // 1.- Creamos el objeto xmlHttpRequest
    xmlHttp = CreateXmlHttp();
   
    // 2.- Definimos la llamada.
    var ajaxRequest = 'receptor.aspx';

    // 3.- Marcar qué función manejará la respuesta
    xmlHttp.onreadystatechange = recogeInfo;
  
    // 4.- Enviar
    xmlHttp.open("POST", ajaxRequest, true);
    xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=ISO-8859-1');
    xmlHttp.send(XML);
}


Cómo veis, poco cambia con respecto al anterior ejemplo. Ahora indicamos explícitamente que queremos que la info se envía vía POST, le hacemos ver al navegador cliente que estamos enviando un formulario y finalmente vemos que el XML se envía dentro de la función send.

3.- Tratar la información en servidor
Tratar la información en servidor es también sencillo.
Recoger la información que se ha enviado no supone más que hacer en Request.QueryString si se ha enviado vía GET o un Request.Form si se ha hecho vía POST.

El modo en que tratemos esa info ya corre por cuenta nuestra, y según si queremos devolver un fichero XML o un simple texto llano haremos una cosa u otra... pero basta de palabreo y veamos un ejemplo:

    private void recogeInfoServidor()
    {
        string info = Request.QueryString["info"];
        //string info = Request.Form[0];
        string XML = Request.Form[0];

        /**************/
        // Tratar INFO
        /**************/

        HttpResponse response = HttpContext.Current.Response;

        response.Clear();
        response.ContentType = "text/plain";
        //response.ContentType = "text/xml";
        response.Write(s);
        response.Flush();
        response.End();
    }


4.- Recoger la información en cliente
Tal y como habíamos indicado en...

    xmlHttp.onreadystatechange = recogeInfo;

... la función que se va a encargar de recoger la info será recogeInfo.

function recogeInfo()
{
    if(xmlHttp.readyState == 4 && xmlHttp.status == 200)
    {
        alert(xmlHttp.responseText);
    }
}

La instancia del XMLHttpRequest tiene dos propiedades muy útiles: readyState y status.

Status es bastante obvia, pues simplemente devuelve el número que indica el resultado de la petición de la página (200 indica que la petición ha sido resulta correctamente). También podemos hacer uso de statusText, que nos devuelve la misma info pero en formato texto (en el caso de 200 devolvería "OK").

ReadyState indica el estado en que se encuentra nuestra petición, y tiene 5 valores diferentes:
0 -> No Inicializado
1 -> Cargando
2 -> Cargado
3 -> Interactuando
4 -> Completado

Finalmente mostramos por pantalla el resultado en modo texto que nos devuelve el servidor mediante response.Text, pero si quisiéramos que nos devolviera el resultado en modo XML para trabajar con éste desde javascript, usaríamos responseXML.