Hace unos dÃas estuve haciendo un módulo que debÃa realizar peticiones asÃncronas a un webservice desde javascript, o dicho de otra forma, el famoso AJAX pero manual, sin usar ninguna librerÃa. Para quien no sepa en qué consiste AJAX, es lo que permite realizar peticiones al servidor sin tener que cargar toda la página; seguro que lo habéis visto en muchos sitios, por ejemplo, al enviar un comentario y ver cómo el mismo se publica sin hacer una recarga completa de la página.
Pues bien, para lograr hacer esto necesitamos utilizar el objeto XMLHttpRequest de nuestro explorador, accederemos a él a través de JavaScript y le enviaremos una petición al servidor. El servidor nos responderá enviándonos los datos en un archivo XML, lo recogemos, lo leemos, y lo mostramos en pantalla haciendo uso de javascript.
Creando el objeto XMLHttpRequest
Vamos por faena, lo primero de todo es… ¿Cómo creamos un objeto XMLHttpRequest? Os muestro el código necesario, en que, como todavÃa no hay un estándard sobre ese objeto (aunque hay un borrador final de la W3C a 15 de Abril de 2008) es necesario meter varias bifurcaciones para crearlo dependiendo del explorador:
function createXmlHttpRequestObject() {
var req = false;
if(window.XMLHttpRequest && !(window.ActiveXObject)) {
try {req = new XMLHttpRequest();}
catch(e) {req = false;}
}
else if(window.ActiveXObject) {
try {req = new ActiveXObject("Msxml2.XMLHTTP");}
catch(e) {
try {req = new ActiveXObject("Microsoft.XMLHTTP");}
catch(e) {req = false;}
}
}
return req;
}
El objeto es el que nos permite hacer peticiones, lo guardaremos en una variable en cada petición de la siguiente manera:
var request; request = apicl_createXmlHttpRequestObject();
Realizando la petición
Una vez que sabemos cómo crear el objeto XMLHttpRequest, es hora de realizar una llamada al servidor, hay que tener en cuenta que en cada llamada al servidor hay que crear un objeto XMLHttpRequest nuevo.
var request; //Esta variable ha de ser global.
function callWS(url, responseHandler, parameters) {
var strParameters = "";
request.onreadystatechange = responseHandler;
request.open("POST", url, true);
if(parameters != null && parameters.length != 0) {
request.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
for(var i = 0; i < parameters.length; i++) {
var p = parameters[i];
if(strParameters != "") strParameters += "&";
strParameters += p[0] + "=" + p[1];
}
}
request.send(strParameters);
}
//Petición sin parámetros:
function getDatos() {
if (document.getElementById('divDatos').innerHTML==''){
request = createXmlHttpRequestObject();
callWS("http://www.entrecodigos.com/service.asmx/getDatos", getResponseDatos, null);
}
}
Voy a intentar explicar los puntos menos claros:
- La propiedad onreadystatechange permite establecer una función de destino cada vez que nuestro objeto XMLHttpRequest cambie de estado, esa función se encargará de recoger la respuesta.
- El método open, permite asignar ciertos valores a nuestra petición: el method (GET, POST o PUT), la url, si va a ser una petición asÃncrona, usuario y contraseña. Los 3 últimos son opcionales.
- La petición puede hacerse con parámetros que requiera la función a la que llamas en el servidor, en ese caso los metemos en una cadena. Luego veremos cómo meter parámetros.
- Realizamos la petición con el método send. Para realizar esta petición se supone que tenemos un webservice al otro lado, es una url a un archivo, el servidor recogerá la petición y la tratará, puedes tener un webservice o hacer una página en aspx manual que reciba las peticiones y devuelva los XML, es preferible lo primero.
Recogiendo la respuesta del servidor
Ahora que ya sabemos cómo llamar al servidor, debemos recoger la respuesta y tratarla, en mi caso lo simplifico haciendo que lo que me pasa el servidor sea una simple cadena de texto que muestro en un div. Como Firefox me dio problemas porque metÃa las respuestas de strings muy largas en varios nodos tuve que crear un bucle:
function getResponse(){
var res = '';
for (var i=0; (i < request.responseXML.documentElement.childNodes.length); i++) {
if (request.responseXML.documentElement.childNodes.item(i))
{res = res + request.responseXML.documentElement.childNodes.item(i).nodeValue;}
}
res = res.replace(/</g, "<").replace(/>/g, ">");
return res;
}
function getResponseDatos() {
if(request.readyState == 4 && request.status == 200) {
document.getElementById('divDatos').innerHTML=getResponse();
}
}
Como se puede ver, conforme el objeto cambie de estado (0: Inicializado, 1: Petición abierta, 2: Petición enviada, 3: Recibiendo respuesta, 4: Respuesta recibida) se irán haciendo llamadas a la función que pusimos receptora, por eso, debemos colocar un filtro que mire en que estado nos encontramos cuando recibimos la llamada. Cuando por fin el estado sea 4, miramos si la respuesta es satisfactoria (200) o si por el contrario ha habido algún tipo de problema (401, 404, …).
Peticiones con parámetros
Por último, os pongo el código completo e incluyo de propina una llamada con parámetros de ejemplo, creo que tras todo lo anterior no necesita explicación.
//Peticiones AsÃncronas:
var request; //Esta variable ha de ser global.
function createXmlHttpRequestObject() {
var req = false;
if(window.XMLHttpRequest && !(window.ActiveXObject)) {
try {req = new XMLHttpRequest();}
catch(e) {req = false;}
}
else if(window.ActiveXObject) {
try {req = new ActiveXObject("Msxml2.XMLHTTP");}
catch(e) {
try {req = new ActiveXObject("Microsoft.XMLHTTP");}
catch(e) {req = false;}
}
}
return req;
}
function callWS(url, responseHandler, parameters) {
var strParameters = "";
request.onreadystatechange = responseHandler;
request.open("POST", url, true);
if(parameters != null && parameters.length != 0) {
request.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
for(var i = 0; i < parameters.length; i++) {
var p = parameters[i];
if(strParameters != "") strParameters += "&";
strParameters += p[0] + "=" + p[1];
}
}
request.send(strParameters);
}
function getResponse(){
var res = '';
for (var i=0; (i < request.responseXML.documentElement.childNodes.length); i++) {
if (request.responseXML.documentElement.childNodes.item(i))
{res = res + request.responseXML.documentElement.childNodes.item(i).nodeValue;}
}
res = res.replace(/</g, "<").replace(/>/g, ">");
return res;
}
//Petición sin parámetros:
function getDatos() {
if (document.getElementById('divDatos').innerHTML==''){
request = createXmlHttpRequestObject();
callWS("http://www.entrecodigos.com/service.asmx/getDatos", getResponseDatos, null);
}
}
function getResponseDatos() {
if(request.readyState == 4 && request.status == 200) {
document.getElementById('divDatos').innerHTML=getResponse();
}
}
//Petición con parámetros:
function getDatosConParam(){
var tipo = document.getElementById('divEjemplo');
if (tipo){
var parameters = new Array();
parameters[0] = new Array("nombreParam1", ejemplo.options[ejemplo.selectedIndex].value);
parameters[1] = new Array("nombreParam2", "valor del param 2");
request = createXmlHttpRequestObject();
callWS("http://www.entrecodigos.com/service.asmx/getDatos", getResponseDatosConParam, parameters);
}
}
function getResponseDatosConParam() {
if(request.readyState == 4 && request.status == 200) {
document.getElementById('divEjemplo').innerHTML=getResponse();
}
}
Notas finales
Para que no os pase como a mi, os aviso de que el javascript sólo podrá hacer peticiones al mismo dominio que ha servido la página por cuestiones de seguridad (phishing y otras historias), esto es, si intentamos llamar a un webservice alojado en www.otraweb.com desde www.miweb.com nos lanzará un error de permisos y nos impedirá el acceso. Para hacer algo como eso debe utilizarse un iframe que cargue una página en www.otraweb.com y lance las peticiones al webservice.
El código que véis lo he picado a mano y nunca lo he probado, es posible que tenga fallos



Podrias ampliar la informacion de como hacer el iframe alojado en “otraweb.com” para lanzar las peticiones?
Gracias