Funcionamiento de XMLHttpRequest en Ajax
Funcionamiento de XMLHttpRequest en Ajax
Grupo MOVIS
Introducción
Para las aplicaciones Ajax y como para la mayor parte de las aplicaciones Web
tradicionales, las transferencias de los datos entre el servidor Web y el cliente
(el navegador) utilizan el protocolo HTTP (HyperText Transfer Protocol). Para
entender mejor el funcionamiento de los mecanismos del objeto
XMLHttpRequest, es interesante hacer un pequeño recordatorio del modo de
funcionamiento de este protocolo ampliamente utilizado en Internet.
1
©ASL Grupo MOVIS
Una solicitud GET puede iniciarse mediante un formulario (el atributo method
se configuraría con el valor de GET) pero también a partir de un simple vínculo
hipertexto al cual se le asociarán con la URL en forma de un par variable/valor
después de un signo de interrogación (ver el siguiente código 1-1).
Código 1-1:
[Link]?message=hola
Código 1-2:
[Link]?message=hola&nombre=pepito
Entre los inconvenientes del método GET, cabe señalar que el tamaño de una
consulta GET se limita a 255 bytes (o 1024 según los sistemas), la cantidad de
información enviada por este método se reduce de tal modo. Además, los
valores que se envían en el URL, por lo tanto son visibles por todos. Las
consultas GET no podrán utilizarse para enviar informaciones voluminosas o si
se debe preservar la confidencialidad de la información.
Sea cual sea el origen de una solicitud GET (formulario o hipervínculo con
parámetros), el servidor recibirá un conjunto de información que consiste en
una línea de solicitud y de varias líneas de encabezado (para las solictudes
GET, el cuerpo de la solicitud es vacío porque los valores se insertan en la
línea de la solicitud, consultar el código 1-4).
Código 1-4: Ejemplo simplificado de una solicitud HTTP con el método GET
iniciado por el URL del código 1-3:
2
©ASL Grupo MOVIS
1: Línea de solicitud
GET /miDirectorio/?message=Hola HTTP/1.1
2: Líneas de encabezado
Host: [Link]
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) Gecko/20050225
➥Firefox/1.0.1
Connection: Keep-Alive
A diferencia del método GET, los valores enviados con el método POST no son
visibles en la barra de direcciones (lo cual es importante si desean enviar
contraseñas por ejemplo...) pero si están considerados en una variable de
entorno insertada en el cuerpo de la solicitud (y por lo tanto invisible para el
usuario). La cantidad de información no está más limitada como en el método
GET y este método ofrece la posibilidad de transmitir flujos de datos con mayor
cantidad de información (hasta 2 GB). Por otra parte, los datos enviados con el
método POST no pueden transmitirse más que con formularios (o con el
método open() de un objeto XMLHttpRequest para aplicaciones Ajax) y no por
una URL como con el método GET.
Código 1-5: Ejemplo simplificado de una solicitud HTTP con el método POST
iniciado por uno formulario que contiene un campo denominado «mensaje»:
1: Línea de solicitud
POST /miDirectorio/ HTTP/1.1
2: Líneas de encabezado
Host: [Link]
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) Gecko/20050225
➥Firefox/1.0.1
Content-type: application/x-www-form-urlencoded
Content-Length: 15
Connection: Keep-Alive
3: Cuerpo de la solicitud
message=Hola
3
©ASL Grupo MOVIS
La respuesta HTTP
La línea de estado (ver la parte 1 del código 1-6) que nos recuerda la versión
del protocolo HTTP (HTTP/1.1 en el ejemplo) seguido del estado de la
respuesta (información importante para Ajax como 200, que significa el éxito de
la operación) y un mensaje complementario (OK por ejemplo).
1 : Linea de estado
HTTP/1.1 200 OK
2 : Lineas de encabezado
Cache-Control: private
Content-type: text/html
Server: GWS/2.1
4
©ASL Grupo MOVIS
3 : Contenido de la respuesta
<html>
<head>
<title>Respuesta</title>
</head>
<body>
Hola
</body>
</html>
Según la respuesta del servidor, el código del estado HTTP puede cambiar.
Veremos a continuación que este código deberá probarse con el script del
motor Ajax para asegurarse que la operación se ha efectuado con éxito. Es por
lo tanto útil conocer los principales códigos del estado HTTP que el servidor
puede reenviar. Estos códigos se detallan en la siguiente tabla.
5
©ASL Grupo MOVIS
6
©ASL Grupo MOVIS
function creationXHR() {
var resultado=null;
try {//prueba para los navegadores : Mozilla, Opera...
resultado= new XMLHttpRequest();
}
catch (Error) {
try {//prueba para los navegadores Internet Explorer > 5.0
resultado= new ActiveXObject("[Link]");
}
catch (Error) {
try {//prueba para el navegador Internet Explorer 5.0
resultado= new ActiveXObject("[Link]");
}
catch (Error) {
resultado= null;
}
}
}
return resultado;
}
La función JavaScript anterior puede ser incorporada directamente en la página
HTML pero tiene más sentido colocarla en un archivo JS externo y vincularla a
continuación en la correspondiente página HTML con la finalidad de poder
disponer de esta fácilmente en las otras páginas del sitio.
var objectXHR = creationXHR();
7
©ASL Grupo MOVIS
Propiedades Descripción
onreadystatechange Designa una función de retrollamada que se llamará cada vez que el
estado de tratamiento de una solicitud asíncrona (readyState) cambiará
de estado.
readyState Estado del tratamiento de una solicitud asíncrona (valor numérico de 0
a 4, ver la tabla 6 para conocer los diferentes estados y su significado).
responseText Contiene el resultado del servidor en formato texto.
responseXml Contiene el resultado del servidor en formato XML.
status Contiene el código del estado HTTP (ejemplo: 200, ver la tabla 1). Este
código está disponible en modo lectura únicamente cuando se ha
transmitido la respuesta.
statusText Contiene el mensaje del estado HTTP (ejemplo: OK, ver tabla 1). Este
texto está disponible en modo lectura únicamente cuando se ha
transmitido la respuesta.
Tabla 4: Propiedades del objeto XMLHttpRequest .
Métodos Descripción
abort() Anula la solicitud en curso.
getAllResponseHeaders() Retorna en una cadena de caracteres todos los
encabezados HTTP contenidos en la respuesta del
servidor. Este método es útil solo cuando el estado del
tratamiento (readyState) es igual a 3 o 4 (Interactive o
Completed).
getResponseHeader(“nombreEncabezado”) Retorna el valor del encabezado cuyo nombre está
indicado en el parámetro (nombreEncabezado). Este
método es útil sólo cuando el estado del tratamiento
(readyState) es igual a 3 o 4 (Interactive o Completed).
open(“metodo”,”url”,”async”) Inicializa el objeto mediante la especificación de algunos
parámetros de la solicitud: el método utilizado (método:
GET o POST), el URL del script del lado del servidor (url:
[Link] por ejemplo) y un tercer parámetro opcional
para indicar si la comunicación debería ser asíncrona
(async: true) o síncrona (async: false).
send(“contenido”) Envía la solicitud. El parámetro (contenido) puede ser nulo
en el caso de una solicitud inicializada con el método GET
o una cadena de solicitud en el caso de un método POST.
Obviamente este método puede usarse sólo cuando el
método open() ya se ha configurado y aun cuando el
estado del tratamiento (readyState) es igual a 1 (Loading).
setRequestHeader(“nombre”, “valor”) Asigna un valor (valor) al encabezado de la solicitud, cuyo
nombre se especifica en el primer parámetro (nombre).
Este método es útil sólo cuando el estado del tratamiento
(readyState) es igual a 1 (Loading).
Tabla 5: Métodos del objeto XMLHttpRequest .
8
©ASL Grupo MOVIS
Códigos educativos
Los distintos códigos de estas notas se han desarrollado para que puedas entender
los mecanismos de una aplicación Ajax de manera progresiva. A menudo están
incompletos y se aconseja no tratar de probarlos en la práctica, sino más bien
concentrarse en su análisis. Más adelante se realizarán prácticas en las que se
implementarán algunas aplicaciones Ajax.
##############-MOTOR AJAX-################
//instanciación del objeto XMLHttpRequest
var objetoXHR = creationXHR();
//----Tratamiento SINCRONO
//Configuración del método utilizado, del script servidor objetivo
//y finalmente la activación del tipo síncrono como último parámetro
[Link]("get","[Link]",false);
//envío de la solicitud
[Link](null);
//recuperación de la respuesta del servidor
var resultado = [Link] ;
….
//El resultado puede ahora insertarse en la página HTML
//si el script servidor corresponde a aquel del cuadro, el valor
//de la variable "resultado" sería entonces igual a "Buenos días"
##############-FIN DEL MOTOR AJAX-################
9
©ASL Grupo MOVIS
En este contexto, la respuesta HTTP del servidor a una solicitud simple (sin
parámetro) podría parecerse al siguiente ejemplo:
HTTP/1.1 200 OK
Cache-Control: private
Content-type: text/plain
Server: GWS/2.1
Date:Tue, 15 May 2013 13:20:24 GMT
Buenos días
10
©ASL Grupo MOVIS
#############-MOTOR AJAX-################
//instanciación del objeto XMLHttpRequest
var objetoXHR = creationXHR();
//Declaración de la función de retrollamada
function tratamientoResultado() {
if([Link]==4) {➋
var resultado = [Link] ;
…
//####El resultado puede ahora insertarse en la página HTML
//si le script del servidor corresponde al del cuadro
//el valor de la variable "resultado" será
//entonces igual a " Buenos días "
}
}
//----Tratamiento ASINCRONO
//Designación de la función de retrollamada
[Link] = tratamientoResultado; ➊
//Configuración del método utilizado, de script servidor objetivo
//y finalmente la activación de tipo asíncrono al final
[Link]("get","[Link]",true);
//envío de la solicitud
[Link](null);
##############-FIN DEL MOTOR AJAX-################
Las anteriores scripts funcionan muy bien siempre y cuando no haya ningún
problema en la transferencia HTTP. Ahora imaginemos que el script del
servidor se elimina o mueve.
En este caso los scripts ya no funcionan y nada indicará la naturaleza del
problema. Sin embargo, el servidor tiene una variable que indica los errores
HTTP, se trata por supuesto del código de estado (ver la tabla 1). Asimismo, el
objeto XMLHttpRequest tiene una propiedad estado (status) que permite leer
fácilmente esta información. Así que vamos a modificar el script de la función
de retrollamada para agregar una segunda prueba y asegurarse de que todo ha
sido correcto antes de usar el resultado (en este caso, la propiedad status debe
ser igual a 200). En caso contrario, mostrará un mensaje de error para informar
a los usuarios.
11
©ASL Grupo MOVIS
##############-MOTO AJAX-################
//instanciación del objeto XMLHttpRequest
var objetoXHR = creationXHR();
//Declaración de la función de retrollamada
function tratamientoResultado() {
if([Link]==4) {
if([Link]==200) {
var resultado = [Link] ;
…
//####El resultado puede ahora insertarse en la página HTML
//si el script del servidor corresponde al del cuadro,
//el valor de la variable "resultado" será
//entonces igual a "Buenos días"
}else {
alert("Error HTTP N˚"+ [Link]);
}
}
}
//----Tratamiento ASINCRONO
//Designación de la function de retrollamada
[Link] = tratamientoResultado;
//Configuración del método utilizado, de script del servidor objetivo
//y finalmente la activación del tipo asíncrono en último parámetro
[Link]("get","[Link]",true);
//envío de la solicitud
[Link](null);
##############-FIN DEL MOTOR AJAX-################
Este método también tiene la ventaja de estimular el desarrollo del script del
lado del servidor, ya que sólo lo llama individualmente en el navegador
añadiendo el parámetro del URL manualmente, seguido su nombre (para ello,
introduce la dirección URL completa en la barra del navegador como por
ejemplo [Link] id = 2). El script entonces
llamado con este parámetro debe mostrar en la pantalla los mismos datos que
luego reenviará enseguida al objeto XMLHttpRequest cuando el sistema estará
operativo (es decir, en nuestro ejemplo "Buenos días señor Smith"). Esta
técnica permite verificar que el script del servidor funciona correctamente y de
direccionar posiblemente las búsquedas hacia el programa JavaScript del lado
del cliente si el problema persiste.
12
©ASL Grupo MOVIS
Del lado del servidor, el parámetro (?id=2, por ejemplo) se recupera a través de
la variable $_REQUEST['id'] antes de ser utilizado en el programa de
construcción del resultado (ver el código 1-12). Entonces este se mostrará en la
pantalla para ser recuperado en modo retardado en la propiedad responseText
de la función de llamada del motor Ajax del lado del cliente (ver la función
tratamientoResultado() del código 1-13).
Para los motores Ajax que incluyen un parámetro en el envío de la solicitud, hemos
modificado ligeramente el script del servidor para que envíe el mensaje correspondiente al
número de identificación del usuario en cuestión.
Código 1-12: Ejemplo del código PHP del archivo [Link]:
<?php
//indica que el tipo de la respuesta reenviada al cliente estará en modo texto
header("Content-Type: text/plain");
//recuperación de la variable GET
if(isset($_REQUEST[’id’])) $id=$_REQUEST[’id’]; else $id=0;
//asignación del nombre que corresponde al identificador
if($id==1) $nom="Díaz";
elseif($id==2) $nom="Smith";
elseif($id==3) $nom="Mariscal";
else $nom="Desconocido";
//formateado y reenvío de la respuesta al cliente
echo "Buenos días señor ".$nom;
?>
En este contexto, la respuesta HTTP del servidor podría parecerse al siguiente ejemplo, si
el parámetro de la solicitud es id=2.
HTTP/1.1 200 OK
Cache-Control: private
Content-type: text/plain
Server: GWS/2.1
Date:Tue, 15 May 2013 13:20:24 GMT
Buenos días señor Smith
##############-MOTOR AJAX-################
//instanciación del objeto XMLHttpRequest
var objetoXHR = creationXHR();
//Declaración de la función de retrollamada
function tratamientoResultado() {
if([Link]==4) {
if([Link]==200) {
var resultado = [Link] ;
…
//####El resultado pude ahora insertarse en la página HTML
//si el script del servidor corresponde al del cuadro,
//el valor de la variable "resultado" será
//entonces igual a "Buenos días señor Smith"
13
©ASL Grupo MOVIS
}else {
alert("Error HTTP N˚"+ [Link]);
}
}
}
//----Tratamiento ASINCRONO - GET
//Designación de la function de retrollamada
[Link] = tratamientoResultado ;
//Configuración del método utilizado, del script servidor con
//los parámetros que se transmiten al servidor
//y finalmente la activación del tipo asíncrono como último parámetro
var numero=2; //simulación de la elección de un número de identificador
[Link]("get","[Link]?id="+numero,true);
//envío de la solicitud
[Link](null);
##############-FIN DEL MOTOR AJAX-################
Sin embargo, hay que tener en cuenta que si deseas enviar tus parámetros al
servidor en XML y no en formato texto bajo la forma de par variable/valor, será
necesario utilizar el método POST para implementar tu aplicación.
14
©ASL Grupo MOVIS
En el dado del servidor no hay diferencia (el archivo del servidor será por lo
tanto como el código 1-12) ya que para la recuperación del parámetro que
utilizamos, la variable HTTP $_REQUEST['id'] sirve para recuperar variables
enviadas por un cliente, independientemente de su método (a diferencia de
$_GET['id'] y $_POST['id'] que se dedican a cada uno de los métodos).
##############-MOTOR AJAX-################
//instanciación del objeto XMLHttpRequest
var objetoXHR = creationXHR();
//Declaración de la función de retrollamada
function tratamientoResultado() {
if([Link]==4) {
if([Link]==200) {
var resultado = [Link] ;
….
//El resultado puede ahora insertarse en la página HTML
//si el script del servidor corresponde al del cuadro,
//el valor de la variable "resultado" será
//entonces igual a "Buenos días señor Smith"
}else {
alert("Error HTTP N˚"+ [Link]);
}
}
}
//----Tratamiento ASINCRONO - POST
//Designación de la function de retrollamada
[Link] = tratamientoResultado ;
//Configuración del método utilizado, del script del servidor objetivo
//y finalmente la activación del tipo asíncrono como último parámetro
[Link]("post","[Link]",true);
//Asignación del tipo de codificado de la solicitud enviada
[Link]("Content-Type","application/x-www-form-urlencoded")
//simulación de la elección del número de identificador
var numero=2;
//envío de la solicitud con un parámetro
[Link](id=numero);
##############-FIN DEL MOTOR AJAX-################
15
©ASL Grupo MOVIS
//---Función de retrollamada
function tratamientoResultado() {
if([Link]==4) {
if([Link]==200) {
var resultado = [Link] ;
}
}
}
[Link] ("MiMensaje").innerHTML
16
©ASL Grupo MOVIS
<script language="JavaScript">
##############-MOTOR AJAX-################
//instanciación del objeto XMLHttpRequest
var objetoXHR = creationXHR();
//Declariación de la función de retrollamada
function tratamientoResultado() {
if([Link]==4) {
if([Link]==200) {
[Link]("miMensaje").innerHTML=[Link] ;
}
}
}
//----Tratamiento ASINCRONO - GET
//Designación de la función de retrollamada
[Link] = tratamientoResultado ;
//Configuración del objeto XHR
[Link]("get","[Link]",true);
//envío de la solicitud
[Link](null);
##############-FIN DEL MOTOR AJAX-################
</script>
…
//antes de la asignación :
<span id="mensaje"></span>
//después de la asignación :
<span id="mensaje"> Buenos días </span>
17
©ASL Grupo MOVIS
<script language="JavaScript">
//-----Controlado de eventos
[Link] = muestraMensaje;
##############-MOTOR AJAX-################
//Declaración del objeto
var objetoXHR;
//Declaración de la función de retrollamada
function tratamientoResultado() {
if([Link]==4) {
if([Link]==200) {
[Link]("miMensaje").innerHTML=[Link] ;
}
}
}
//Declaración de la función de llamada del motor Ajax
function muestraMensaje() {
//Instanciación del objeto XMLHttpRequest
objetoXHR = creationXHR();
//Designación de la función de retrollamada
[Link] = tratamientoResultado ;
//Configuración del objeto XHR
[Link]("get","[Link]",true);
//Envío de la solicitud
[Link](null);
}
##############-FIN DEL MOTOR AJAX-################
</script>
…
//antes de que se haya presionado una tecla :
<span id="mensaje"></span>
//después de haber presionado una tecla :
<span id="mensaje"> Buenos días </span>
…
18