Mantener una Sesión en HTTP

miércoles, 10 de agosto de 2011 Etiquetas: , , , , , ,

Introducción

En la anterior entrada del blog vimos como realizar una conexión a un servidor http y leer la información que nos envía. Esto nos funciona para peticiones simples, donde realizamos una llamada y el servidor nos contesta. La parte servidor no necesita almacenar datos sobre nuestra conexión.

Hay ocaciones, sin embargo, que nuestra aplicación necesita realizar una serie de peticiones al servidor y este si que necesita mantener información de la conexión para poder respondernos. En este caso el servidor necesita inciar una sesión donde poder almacenar información y que al realizar la llamada debemos indicarle el id de la sesión. Vamos a
ver como podemos realizar este funcionamiento mediante el uso de cookies [1].


Manteniendo la sesión.
En el postanterior vimos como crear una funcion para leer la respuesta del servidor http a nuestra petición. En esta ocasión vamos a hacer un clase que sea capaz de mantener una sesión mediante el uso de cookies. Además haremos que esta clase implemente el patrón de diseño [2] Singleton [3] para permitir un acceso único en nuestra aplicación.


public final class Conexion { 
  static private Conexion conexion = null;  
  private String cookieSession     = "";

  /** Contructor privado, no se permite instanciarlo directamente*/
  private Conexion(){
  }

  /** Devuelve la instancia de la conexión actual. 
      Se utiliza para mantener la sesión.*/
  static public Conexion getConexion() {
    if (conexion == null) conexion = new Conexion();        
      return conexion;
  }

  public String leer_url(String direccion){
        URL url = new URL(direccion);
 HttpURLConnection conexion=(HttpURLConnection)url.openConnection();

 /*Asigno algunas propiedades a la conexión*/
 conexion.setRequestMethod("GET");
 conexion.setRequestProperty("Content-Language","es-ES");

 /*Si se ha leido una cookie de sesion la envíamos en la cabecera */
 if (!Util.isEmpty(cookieSession))          
   conexion.setRequestProperty("cookie", cookieSession);
    
 int httpResponseCode = conexion.getResponseCode();         
 if (httpResponseCode == HttpURLConnection.HTTP_OK){
            /*Compruebo si hay una cookie guardada*/
         if (Util.isEmpty(cookieSession)){                      
       String cookie = conexion.getHeaderField("set-cookie");
    if(!Util.isEmpty(cookie)){                  
      int semicolon = cookie.indexOf(';');
                    cookieSession = cookie.substring(0, semicolon);                  
    }                 
            }
 }
  
 /*La lectura de datos la hago leyendo bytes
 Así puedo descargar ficheros que no son texto, en este caso 
 lo convertiré después a texto*/
 InputStream input;
 StringBuffer responseBuffer = new StringBuffer();
 try {     
   input = new BufferedInputStream(conexion.getInputStream(),1024);    
                  
   byte[] byteArray = new byte[1024]; 
   int leidos=0;
   while ( (leidos=input.read(byteArray))>0){      
   String res = new String(byteArray, "iso-8859-1");           
          responseBuffer.append(res.substring(0,leidos));
   byteArray = null;
   byteArray = new byte[1024];             
   }           
   String response = responseBuffer.toString(); 
   /*Liberamos las conexiones y entrada de datos.
     Si no se hace puede dar problemas después de varias conexiones.*/
   input.close(); 
   conexion.disconnect();         
   conexion=null;
   return response;
 }
  }
}

Si observamos comparamos el código de esta función con la anterior veremos que la única diferencia es la lectura de la cookie de sesión y su asignación en caso que se haya leido. Esta es la parte diferente.


/*Si se ha leido una cookie de sesion la envíamos en la cabecera */
if (!Util.isEmpty(cookieSession))          
 conexion.setRequestProperty("cookie", cookieSession);
    
int httpResponseCode = conexion.getResponseCode();         
if (httpResponseCode == HttpURLConnection.HTTP_OK){
 /*Compruebo si hay una cookie guardada*/
 if (Util.isEmpty(cookieSession)){                      
  String cookie = conexion.getHeaderField("set-cookie");
  if(!Util.isEmpty(cookie)){                  
   int semicolon = cookie.indexOf(';');
   cookieSession = cookie.substring(0, semicolon);                  
  }                 
 }
}

La función Util.isEmpty simplemente comprueba si la varible String es null o esta vacía, si cumple una de estas condiciones devuelve true indicando que esta vacía.

Para implementar el diseño del patrón Singleton declaramos el constructor de la clase como privada, de esta forma impedimos que se pueda instanciar. Para obtener una instancia de nuestra clase Conexion deberemos llamar a la función getConexion() que nos devolverá la instancia si esta creada, y sino la creará y la devolverá.

En esta entrada hemos visto la utilización del patrón Singleton, que para ciertas cosas es muy útil, además de tener una implementación sencilla como hemos visto. También hemos vistos como mantener una sesión mediante la utilización de cookies. Ahora nuestra aplicación Android podrá mantener una sesión en nuestras conexiones. En esta clase una vez obtenida la respuesta libero las conexión http, eso ya es cosa vuestra decidir hacerlo igual o no.



Bibliografía y Enlaces
[1]Wikipedia (2011) Http cookie (inglés)
[2]Wikipedia (2011) Patrones de diseño(castellano)
[3]Wikipedia (2011) Patrón Singleton(castellano)
[*]IETF(Abril 2011) RFC6265 (inglés)

0 comentarios:

Publicar un comentario