Prácticas

Para las siguientes prácticas se indicarán los siguientes puntos a desarrollar por cada una:

  • Cada práctica contará con su propio directorio ráiz: $HOME/www/xhr0x
  • Cada práctica contará con un nombre de host: xhr0x.com
  • Cada práctica contará con un puerto TCP: 808x
  • En base al nombre de host se tendrá un URL: http://xhr0x.com:808x
  • El servidor web a usar es thttpd:

     alumno@servidor:~ $ cd $HOME/www/xhr0x
     alumno@servidor:~ $ thttpd -D -p 808x -T UTF-8 -nor -l -
    

Para configurar el nombre de host tienes que asociar la dirección ip 127.0.0.1 a xhr0x.com (según sea el caso) en el archivo /etc/hosts del sistema operativo.

Práctica 01

  • Directorio ráiz: $HOME/www/xhr01.
  • Puerto TCP: 8081
  • Nombre de host: xhr01.com
  • URL: http://xhr01.com:8081

Esta práctica plantea la descarga de un documento XML haciendo uso de XMLHttpRequest.

  1. De http://www.sepomex.gob.mx/lservicios/servicios/CodigoPostal_Exportar.aspx descarga los códigos postales de algún estado en formato XML. Te recomiendo que trabajes con Baja California Sur ya que contiene menos cantidad de códigos postales.

    Notas:

    • En el caso de Baja California Sur el archivo que entrega el servidor solo tiene por nombre Baja, descargalo y renombralo a BajaCaliforniaSur.xml.
    • En base al contenido de los archivos en formato XML, estos han sido generados desde Microsoft SQL Server mediante el uso de DataSets (ADO.NET).
  2. Crea el directorio xml y en él deposita el archivo descargado en el anterior paso.

  3. Crea el archivo index.html con el siguiente contenido:

    <!DOCTYPE html>
    <html>
      <head>
        <meta charset="UTF-8">
        <title>xhr01</title>
        <style>
          body {
            width: 960px;
            margin: 10px auto 30px auto;
          }
          #archivo_a_descargar {
            width: 100%;
          }
          #archivo_descargado {
            width: 100%;
            height: 200px;
          }
          #mensaje {
            color: red;
          }
        </style>
      </head>
      <body onload="iniciar();">
        <h1>xhr01</h1>
          <form id="formulario">
            <fieldset>
              <legend>Entidades</legend>
                <label for="archivo">Seleccione una entidad:</label>
                <select id="archivo_a_descargar">
                  <option value="Aguascalientes.xml">Aguascalientes</option>
                  <option value="BajaCalifornia.xml">Baja California</option>
                  <option value="BajaCaliforniaSur.xml">Baja California Sur</option>
                  <option value=""></option>
                  <option value="Oaxaca.xml">Oaxaca</option>
                  <option value="EntidadQueNoExiste.xml">Entidad Que No Existe</option>
                  <option value="Zacatecas.xml">Zacatecas</option>
                </select>
                <input type="button" value="Descargar" id="descargar" />
            </fieldset>
          </form>
        <h1>Resultado:</h1>
        <p id="mensaje"></p>
        <textarea id="archivo_descargado"></textarea>
      <script src="js/xhr01a.js"></script>
      </body>
    </html>
    
  4. Crea el directorio js y en él el archivo xhr01a.js con el siguiente contenido:

    var descargar = function(evento) {
      var archivo_a_descargar = document.getElementById("archivo_a_descargar");
      var archivo_descargado = document.getElementById("archivo_descargado");
      var mensaje = document.getElementById("mensaje");
      archivo_descargado.value = "";
      mensaje.textContent = "";
      if (! /^\w+\.xml$/.test(archivo_a_descargar.value)) {
         mensaje.textContent = "Seleccione una entidad.";
         return false;
      }
      var servidor = "http://xhr01.com:8081";
      var url = servidor + "/xml/" + archivo_a_descargar.value + "?r=" + Math.random();
      var xhr = new XMLHttpRequest();
      xhr.onreadystatechange = function() {
        if (this.readyState === 4) {
          var archivo_descargado = document.getElementById("archivo_descargado");
          var mensaje = document.getElementById("mensaje");
          archivo_descargado.value = "";
          mensaje.textContent = "";
          if (this.status === 200) {
              archivo_descargado.value = this.responseText;
          } else {
              mensaje.textContent = "Error " + this.status + " " + this.statusText + " - " + this.responseURL;
          }
        }
      };
      xhr.open('GET', url, true);
      xhr.send();
    };
    var iniciar = function() {
      var boton_descargar = document.getElementById("descargar");
      boton_descargar.addEventListener('click', descargar, false);
    };
    
  5. Accede a http://xhr01.com:8081 y mientras tengas abierto a Console selecciona a Baja California Sur del formulario mostrado y da clic sobre el botón Descargar.

Descargua los códigos postales de los demás estado siguiendo la misma pauta dada para Baja California Sur, tomando en cuenta de no usar letras acentuadas en el nombre de los archivos, y actualiza el elemento <select> encontrado en el archivo index.html.

Al finalizar tendrás una estructura similar a:

alumno@servidor:~/www/xhr01 $ pwd && tree
/home/alumno/www/xhr01
.
├── index.html
├── js
│   └── xhr01a.js
└── xml
    ├── Aguascalientes.xml
    ├── BajaCaliforniaSur.xml
    ├── BajaCalifornia.xml
    ├── ...
    ├── VeracruzDeIgnacioDeLaLlave.xml
    ├── Yucatan.xml
    └── Zacatecas.xml
2 directories, 34 files

Práctica 02

  • Directorio ráiz: $HOME/www/xhr02.
  • Puerto TCP: 8082
  • Nombre de host: xhr02.com
  • URL: http://xhr02.com:8082

Esta práctica plantea el recorrido de un documento XML así como acceder a su contenido y generar a partir de él una tabla de HTML (<table>).

  1. Crea el archivo index.html el siguiente contenido:

    <!DOCTYPE html>
    <html>
      <head>
        <meta charset="UTF-8">
        <title>xhr02</title>
        <style>
          body {
            width: 960px;
            margin: 10px auto 30px auto;
          }
          #archivo_a_descargar {
            width: 100%;
          }
          #archivo_descargado {
            width: 100%;
            height: 200px;
          }
          #mensaje {
            color: red;
          }
          #resultado {
            width: 100%;
            font-family: sans-serif;
            color: #000;
            font-size: 7px;
            background: #ccc;
            margin: 0;
            border: #aaa 1px solid;
          }
          #resultado tr {
            text-align: center;
          }
          #resultado th {
            border-top: 1px solid #fafafa;
            border-bottom:1px solid #e0e0e0;
            background: #ededed;
            text-align: center;
          }
          #resultado td {
            border-top: 1px solid #ffffff;
            border-bottom:1px solid #e0e0e0;
            border-left: 1px solid #e0e0e0;
            background: #fafafa;
            text-align: center;
          }
          #resultado tr.even td {
            background: #f6f6f6;
          }
          #resultado tr:hover td {
            background: #f2f2f2;
          }
        </style>
      </head>
      <body onload="iniciar();">
        <h1>xhr02</h1>
          <form id="formulario">
            <fieldset>
              <legend>Entidades</legend>
                <label for="archivo">Seleccione una entidad:</label>
                <select id="archivo_a_descargar">
                  <option value="Aguascalientes.xml">Aguascalientes</option>
                  <option value="BajaCalifornia.xml">Baja California</option>
                  <option value=""></option>
                  <option value="EntidadQueNoExiste.xml">Entidad Que No Existe</option>
                  <option value="BajaCaliforniaSur.xml">Baja California Sur</option>
                  <option value=""></option>
                  <option value="Zacatecas.xml">Zacatecas</option>
                </select>
                <input type="button" value="Descargar" id="descargar" />
            </fieldset>
          </form>
        <h1>Resultado: <span id="cantidad_de_codigos_postales"></span></h1>
        <p id="mensaje"></p>
        <table id="resultado"><thead></thead><tbody></tbody></table>
      <script src="js/xhr02a.js"></script>
      </body>
    </html>
    
  2. Crea el archivo js/xhr02a.js con el siguiente contenido:

    var actualizarTabla = function(documento_xml) {
      /* Para acceder al DOM de documento_xml en Console: */
      console.log("Documento: " + documento_xml.URL);
      console.log(documento_xml);
      /* Eliminación de thead y tbody de table */
      var tabla = document.getElementById("resultado");
      if (tabla.firstChild && tabla.lastChild) {
        tabla.removeChild(tabla.firstChild);
        tabla.removeChild(tabla.lastChild);
      }
      /* Cabecera (<thead>) de la tabla
       * El siguiente documento PDF indica los campos que conforman la información
       * por cada estado:
       * http://www.correosdemexico.gob.mx/lservicios/servicios/imagenes%5CDescrip.pdf
       */
      var campos = [];
      var xml_campos_primer_estado = documento_xml.firstChild.childNodes[1].childNodes;
      var tabla_thead = document.createElement("thead");
      tabla.appendChild(tabla_thead);
      var tabla_tr = document.createElement("tr");
      tabla_thead.appendChild(tabla_tr);
      var tabla_th = document.createElement("th");
      tabla_th.textContent = "#";
      tabla_tr.appendChild(tabla_th); 
      for (var i = 0; i < xml_campos_primer_estado.length; i++ ) {
        var tabla_th = document.createElement("th");
        tabla_th.textContent = xml_campos_primer_estado[i].nodeName;
        tabla_tr.appendChild(tabla_th); 
        campos.push(xml_campos_primer_estado[i].nodeName); 
      }
      /* Cuerpo (<tbody>) de la tabla */
      var xml_nodos = documento_xml.firstChild.childNodes;
      var tabla_tbody = document.createElement("tbody");
      tabla.appendChild(tabla_tbody);
      for (var i = 1; i < xml_nodos.length; i++) {
        /* Contador */
        var tabla_tr = document.createElement("tr");
        var tabla_contador = document.createElement("td");
        tabla_contador.textContent = i;
        tabla_tr.appendChild(tabla_contador);
        /* Campos por estado */
        var nodo_elemento = xml_nodos[i].childNodes;
        for (var j=0; j < campos.length; j++) {
          var tabla_td = document.createElement("td");
          if (nodo_elemento[j] && campos[j] === nodo_elemento[j].nodeName) {
            tabla_td.textContent = nodo_elemento[j].textContent;
          } else {
            /* Si el estado no cuenta con este campo */
            tabla_td.textContent = "N/A";
          }
          tabla_tr.appendChild(tabla_td);
        }
        tabla_tbody.appendChild(tabla_tr);
      }
      var cantidad_de_codigos_postales = document.getElementById("cantidad_de_codigos_postales");
      cantidad_de_codigos_postales.textContent = (i - 1) + " códigos postales";
    }
    var descargar = function(evento) {
      var archivo_a_descargar = document.getElementById("archivo_a_descargar");
      var mensaje = document.getElementById("mensaje");
      var cantidad_de_codigos_postales = document.getElementById("cantidad_de_codigos_postales");
      var tabla = document.getElementById("resultado");
      mensaje.textContent = "";
      cantidad_de_codigos_postales.textContent = "";
      /* Eliminación de thead y tbody de table */
      if (tabla.firstChild && tabla.lastChild) {
        tabla.removeChild(tabla.firstChild);
        tabla.removeChild(tabla.lastChild);
      }
      if (! /^\w+\.xml$/.test(archivo_a_descargar.value)) {
        mensaje.textContent = "Seleccione una entidad.";
        return false;
      }
      var servidor = "http://xhr02.com:8082";
      var url = servidor + "/xml/" + archivo_a_descargar.value + "?r=" + Math.random();
      var xhr = new XMLHttpRequest();
      xhr.onreadystatechange = function() {
        if (this.readyState === 4) {
          var mensaje = document.getElementById("mensaje");
          var cantidad_de_codigos_postales = document.getElementById("cantidad_de_codigos_postales");
          mensaje.textContent = "";
          cantidad_de_codigos_postales.textContent = "";
          if (this.status === 200) {
            actualizarTabla(xhr.responseXML);
          } else {
              mensaje.textContent = "Error " + this.status + " " + this.statusText + " - " + this.responseURL;
          }
        }
      };
      xhr.open('GET', url, true);
      xhr.send();
    };
    var iniciar = function() {
      var boton_descargar = document.getElementById("descargar");
      boton_descargar.addEventListener('click', descargar, false);
    };
    
  3. Crea el directorio xml y deposita en él todos los archivos xml con los códigos postales obtenidos en la anterior práctica. Actualiza el archivo index.html de igual forma.

  4. Accede a http://xhr02.com:8082 y realiza lo mismo que en la práctica anterior.

Práctica 03

  • Directorio ráiz: $HOME/www/xhr03.
  • Puerto TCP: 8083
  • Nombre de host: xhr03.com
  • URL: http://xhr01.com:8083

Sobre el envío de datos al servidor mediante el objeto XMLHttpRequest y los métodos GET y POST de HTTP.

El uso de Python en el lado del servidor es solo para demostración de la recepción de los datos capturados en el formulario de HTML usando al objeto XMLHttpRequest, pero además del como el objeto XMLHttpReques puede hacer algo con los datos recibidos del servidor. Es posible tener cualquier otro lenguaje de programación en el lado del servidor.

  1. Crea el archivo index.html con el siguiente contenido:

    <!DOCTYPE html>
    <html>
      <head>
        <meta charset="UTF-8">
        <title>xhr03</title>
        <style>
          body {
            width: 960px;
            margin: 10px auto 30px auto;
          }
          #archivo_a_descargar {
            width: 100%;
          }
          #respuesta {
            width: 100%;
            background-color: #f2f2f2;
          }
          #mensaje {
            color: red;
          }
        </style>
      </head>
      <body onload="App.main();">
        <h1>xhr03</h1>
        <form id="formulario">
          <fieldset>
            <legend>Formulario</legend>
            <p>
              <label for="nombre">Nombre:</label>
              <input type="text" id="nombre" />
            </p>
            <p>
              <label for="nacimiento">Año de nacimiento:</label>
              <input type="text" id="nacimiento" />
            </p>
            <p>
              <label for="metodo_http">Método HTTP:</label>
              <select id="metodo_http">
                <option value="GET">GET</option>
                <option value="POST">POST</option>
              </select>
            </p>
            <p>
              <input type="button" value="Enviar" id="descargar" />
           </p>
          </fieldset>
        </form>
        <h1>Resultado:</h1>
        <pre id="respuesta"></pre>
        <p id="mensaje"></p>
        <script src="js/xhr03a.js"></script>
      </body>
    </html>
    
  2. Crea el archivo js/xhr03a.js con el siguiente contenido:

    var App = (
      function() {
        var _descargar = function(evento) {
          var url = "http://xhr03.com:8083/cgi-bin";
          var xhr = new XMLHttpRequest();
          xhr.onreadystatechange = _procesarCambioDeEstado(xhr);
          var parametros = "nombre=" +
            document.getElementById("nombre").value + "&" +
            "nacimiento=" +
            document.getElementById("nacimiento").value;
          if (document.getElementById("metodo_http").value === "GET") {
            xhr.open('GET', url + "/get.py" + "?" + parametros);
            xhr.send();
          } else {
            xhr.open('POST', url + "/post.py");
            xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
            xhr.setRequestHeader("Content-Length", parametros.length);
            xhr.setRequestHeader("Connection", "close");
            xhr.send(parametros);
          }
        }
        var _procesarCambioDeEstado = function(objeto_XMLHttpRequest) {
          return function() {
            var respuesta = document.getElementById("respuesta");
            var mensaje = document.getElementById("mensaje");
            respuesta.textContent = "";
            mensaje.textContent = "";
            if (objeto_XMLHttpRequest.readyState === 4) {
              if (objeto_XMLHttpRequest.status === 200) {
                  respuesta.textContent = objeto_XMLHttpRequest.responseText;
              } else {
                  mensaje.textContent = "Error " + this.status + " " + this.statusText + " - " + this.responseURL;
              }
            }
          };
        }
        var _main = function() {
          var boton_descargar = document.getElementById("descargar");
          boton_descargar.addEventListener('click', _descargar, false);
        }
        return { "main": _main };
      }
    )();
    
  3. Crea el archivo servidor.py con el siguiente contenido:

    #!/usr/bin/env python3
    import http.server
    puerto = 8083
    servidor = http.server.HTTPServer(("", puerto), http.server.CGIHTTPRequestHandler)
    try:
      print("Atendiendo solicitudes en ", puerto)
      servidor.serve_forever()
    except KeyboardInterrupt:
      print("Deteniendo servidor...")
      servidor.socket.close()
    
  4. Crea el directorio cgi-bin y en él los archivos get.py y post.py con el siguiente contenido en ambos casos:

    #!/usr/bin/env python3
    import os, cgi
    solicitud = cgi.FieldStorage()
    agente_de_usuario = os.environ["HTTP_USER_AGENT"]
    referencia_http = os.environ["HTTP_REFERER"]
    archivo_cgi = os.environ["SCRIPT_NAME"]
    nombre = ""
    nacimiento = ""
    if "nombre" in solicitud:
      nombre = solicitud["nombre"].value
    if "nacimiento" in solicitud:
      nacimiento = solicitud["nacimiento"].value
    print("Content-Type: text/plain")
    print("")
    print("Servidor:", referencia_http)
    print("Script:", archivo_cgi)
    print("Agente de usuario:", agente_de_usuario)
    print("")
    print("nombre =", nombre)
    print("nacimiento =", nacimiento)
    
  5. Asigna permisos de ejecución a los archivos cgi-bin/get.py y cgi-bin/post.py:

    alumno@servidor:~/www/xhr03 $ chmod +x cgi-bin/get.py cgi-bin/post.py
    

    Hasta este punto tendrás la siguiente estructura en $HOME/www/xhr03:

    alumno@servidor:~/www/xhr03 $ pwd && tree
    /home/alumno/www/xhr03
    .
    ├── cgi-bin
    │   ├── get.py
    │   └── post.py
    ├── index.html
    ├── js
    │   └── xhr03a.js
    └── servidor.py
    2 directories, 5 files
    
  6. Inicia el servidor web haciendo uso de Python:

    alumno@servidor:~/www/xhr03 $ python3 servidor.py
    
  7. Accede a http://xhr03.com:8083, rellena el formulario, selecciona alguna de las opciones de Método HTTP, da clic al botón Enviar y revisa el documento HTML obtenido desde el servidor.

Observaciones:

  • El formulario en index.html no define sus atributos method y action.
  • Podrías generar un documento XML de forma dinámica desde el lado del servidor y solicitar dicho documento desde el lado del cliente. En el lado del cliente (Navegador Web + JavaScript + DOM + XMLHttpRequest) crear una Interfaz Gráfica de Usuario que interactue con el lado del servidor.