El descriptor de implementación: web.xml

Las aplicaciones web de Java usan un archivo descriptor de implementación para determinar cómo se asignan las URL en los servlets, qué URL requieren autenticación y más información. Este archivo se llama web.xml, y se encuentra en el WAR de la app en el directorio WEB-INF/ . web.xml es parte del servlet estándar para aplicaciones web.

Para obtener más información acerca del web.xml estándar, consulta la wiki de referencia sobre Metawerx web.xml y la especificación de Servlet.

Descriptores de implementación

Un descriptor de implementación de una aplicación web describe las clases, recursos y configuración de la aplicación y la forma en que los usa el servidor web para entregar solicitudes web. Cuando el servidor web recibe una solicitud para la aplicación, usa el descriptor de implementación a fin de asignar la URL de la solicitud al código que debe manejarla.

El descriptor de implementación es un archivo llamado web.xml. Se encuentra en el WAR de la app, en el directorio WEB-INF/. El archivo es un archivo XML cuyo elemento raíz es <web-app>.

Aquí hay un simple ejemplo de web.xml que asigna todas las rutas de URL (/*) a la clase del servlet mysite.server.ComingSoonServlet:

<web-app xmlns="http://java.sun.com/xml/ns/javaee" version="2.5">
    <servlet>
        <servlet-name>comingsoon</servlet-name>
        <servlet-class>mysite.server.ComingSoonServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>comingsoon</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>
</web-app>

Servlets y rutas de URL

web.xml define las asignaciones entre las rutas de URL y los servlets que manejan las solicitudes con esas rutas. El servidor web usa esta configuración para identificar el servlet que maneja una solicitud determinada y llamar al método de clase que corresponde al método de la solicitud. Por ejemplo: el método doGet() para las solicitudes de HTTP GET.

Para asignar una URL a un servlet, decláralo con el elemento <servlet> y luego define una asignación de una ruta de URL a una declaración de servlet con el elemento<servlet-mapping>.

El elemento <servlet> declara el servlet, que incluye un nombre usado por otros elementos para referirse al servlet en el archivo, la clase que usará el servlet y los parámetros de inicialización. Puedes declarar varios servlets con la misma clase, pero con diferentes parámetros de inicialización. El nombre de cada servlet debe ser único en todo el descriptor de implementación.

    <servlet>
        <servlet-name>redteam</servlet-name>
        <servlet-class>mysite.server.TeamServlet</servlet-class>
        <init-param>
            <param-name>teamColor</param-name>
            <param-value>red</param-value>
        </init-param>
        <init-param>
            <param-name>bgColor</param-name>
            <param-value>#CC0000</param-value>
        </init-param>
    </servlet>

    <servlet>
        <servlet-name>blueteam</servlet-name>
        <servlet-class>mysite.server.TeamServlet</servlet-class>
        <init-param>
            <param-name>teamColor</param-name>
            <param-value>blue</param-value>
        </init-param>
        <init-param>
            <param-name>bgColor</param-name>
            <param-value>#0000CC</param-value>
        </init-param>
    </servlet>

El elemento <servlet-mapping> especifica un patrón de URL y el nombre de un servlet declarado para usar en solicitudes cuyas URL coincidan con el patrón. El patrón de URL puede usar un asterisco (*) al principio o al final del patrón para indicar cero o más de cualquier carácter. El estándar no admite comodines en medio de una string y no permite varios comodines en un solo patrón. El patrón coincide con la ruta completa de la URL, incluida la barra diagonal (/) que sigue al nombre de dominio. La ruta de URL no puede comenzar con un punto (.).

    <servlet-mapping>
        <servlet-name>redteam</servlet-name>
        <url-pattern>/red/*</url-pattern>
    </servlet-mapping>

    <servlet-mapping>
        <servlet-name>blueteam</servlet-name>
        <url-pattern>/blue/*</url-pattern>
    </servlet-mapping>

En este ejemplo, la clase TeamServlet controla la solicitud para la URL http://www.example.com/blue/teamProfile con el parámetro teamColor igual a blue y el parámetro bgColor igual a #0000CC. El servlet puede obtener la porción de la ruta de URL que coincide con el comodín con el método getPathInfo() del objeto ServletRequest.

El servlet puede acceder a los parámetros de inicialización cuando obtiene su configuración de servlet mediante su propio método getServletConfig() , y luego llamar al método getInitParameter() en el objeto de configuración con el nombre del parámetro como argumento.

String teamColor = getServletConfig().getInitParameter("teamColor");

JSP

Una app puede usar JavaServer Pages (JSP) para implementar páginas web. Los JSP son servlets definidos mediante contenido estático como HTML mezclado con código Java.

App Engine admite la compilación automática y la asignación de URL para JSP. Un archivo JSP en el WAR de la aplicación (fuera de WEB-INF/), cuyo nombre de archivo termina en .jsp, se compila en una clase de servlet de manera automática y se le asigna la ruta de URL equivalente a la ruta del archivo JSP desde la raíz del WAR. Por ejemplo, si una app tiene en su WAR un archivo JSP con el nombre start.jsp en un subdirectorio llamado register/, App Engine lo compila y le asigna la ruta de URL /register/start.jsp.

Para tener más control sobre cómo se asigna el JSP a una URL, puedes especificar la asignación de manera explícita si la declaras con un elemento <servlet> en el descriptor de implementación. En lugar de un elemento <servlet-class>, debes especificar un elemento <jsp-file> con la ruta del archivo JSP desde la raíz del WAR. El elemento <servlet> para el JSP puede contener parámetros de inicialización.

    <servlet>
        <servlet-name>register</servlet-name>
        <jsp-file>/register/start.jsp</jsp-file>
    </servlet>

    <servlet-mapping>
        <servlet-name>register</servlet-name>
        <url-pattern>/register/*</url-pattern>
    </servlet-mapping>

Puedes instalar bibliotecas de etiquetas JSP con el elemento <taglib>. Una biblioteca de etiquetas tiene una ruta al archivo Descriptor de bibliotecas de etiquetas (TLD) JSP (<taglib-location>) y una URI que los JSP usan para seleccionar la biblioteca que se cargará (<taglib-uri>). Ten en cuenta que App Engine proporciona la Biblioteca de etiquetas estándar de JavaServer Pages (JSTL) y no necesitas instalarla.

    <taglib>
        <taglib-uri>/escape</taglib-uri>
        <taglib-location>/WEB-INF/escape-tags.tld</taglib-location>
    </taglib>

Seguridad y autenticación

Una aplicación de App Engine puede usar Cuentas de Google para la autenticación de usuarios. La app puede usar la API de Cuentas de Google para detectar si un usuario accedió a su cuenta, obtener la dirección de correo electrónico del usuario que tiene acceso en ese momento y generar las URL de inicio y cierre de sesión. Una aplicación también puede especificar restricciones de acceso para rutas de URL basadas en Cuentas de Google mediante el descriptor de implementación.

El elemento <security-constraint> define una restricción de seguridad para las URL que coinciden con un patrón. Si un usuario que no ingresó aún accede a una URL cuya ruta tiene una restricción de seguridad, App Engine redirecciona al usuario a la página de acceso de Cuentas de Google. Cuentas de Google vuelve a redireccionar al usuario a la URL de la aplicación después de que este acceda a la cuenta de manera exitosa o cree una cuenta nueva. La app no necesita ninguna acción adicional para asegurarse de que solo los usuarios registrados tienen acceso a la URL.

Una restricción de seguridad incluye una restricción de autorización que especifique qué usuarios de Cuentas de Google pueden acceder a la ruta. Si la restricción de autorización especifica una función de usuario de *, cualquier usuario que haya ingresado con una Cuenta de Google puede acceder a la URL. Si la restricción especifica una función de usuario de admin, solo pueden acceder a la URL los desarrolladores registrados de la aplicación. La función admin facilita crear secciones exclusivas para el administrador de tu sitio.

    <security-constraint>
        <web-resource-collection>
            <web-resource-name>profile</web-resource-name>
            <url-pattern>/profile/*</url-pattern>
        </web-resource-collection>
        <auth-constraint>
            <role-name>*</role-name>
        </auth-constraint>
    </security-constraint>

    <security-constraint>
        <web-resource-collection>
            <web-resource-name>admin</web-resource-name>
            <url-pattern>/admin/*</url-pattern>
        </web-resource-collection>
        <auth-constraint>
            <role-name>admin</role-name>
        </auth-constraint>
    </security-constraint>

App Engine no admite funciones de seguridad personalizadas (<security-role>) o mecanismos de autenticación alternativos (<login-config>) en el descriptor de implementación.

Las restricciones de seguridad aplican a los archivos estáticos y a los servlets.

URL seguras

Google App Engine admite conexiones seguras a través de HTTPS para URL mediante el dominio *.appspot.com. Cuando una solicitud accede a una URL mediante HTTPS, y la URL está configurada para usar HTTPS en el archivo web.xml, el remitente encripta los datos solicitados y los datos de respuesta antes de su envío, y el receptor los desencripta luego de recibirlos. Las conexiones seguras son útiles para proteger los datos del cliente como información de contacto, contraseñas y mensajes privados.

Si quieres declarar que se debe usar HTTPS para una URL, debes configurar una restricción de seguridad en el descriptor de implementación (como se describe en Seguridad y autenticación) con un <user-data-constraint> cuyo <transport-guarantee> sea CONFIDENTIAL. Por ejemplo:

    <security-constraint>
        <web-resource-collection>
            <web-resource-name>profile</web-resource-name>
            <url-pattern>/profile/*</url-pattern>
        </web-resource-collection>
        <user-data-constraint>
            <transport-guarantee>CONFIDENTIAL</transport-guarantee>
        </user-data-constraint>
    </security-constraint>

Las solicitudes que usen HTTP (no seguro) para URL cuya garantía de transporte es CONFIDENTIAL, se redireccionan de manera automática a la misma URL mediante HTTPS.

Cualquier URL puede usar la garantía de transporte CONFIDENTIAL, incluso los JSP y los archivos estáticos.

El servidor web de desarrollador no admite conexiones HTTPS. Este ignora la garantía de transporte para que las rutas destinadas a usarse con HTTPS puedan probarse mediante conexiones HTTP regulares al servidor web de desarrollador.

Cuando pruebas los controladores HTTPS de tus aplicaciones mediante la URL con versión appspot.com, como https://1.latest.<i>your_app_id</i>.appspot.com/, el navegador te advierte que el certificado HTTPS no se registró para esa ruta de dominio específica. Si aceptas el certificado para ese dominio, las páginas se cargarán con éxito. Los usuarios no verán la advertencia del certificado cuando accedan a https://<i>your_app_id</i>.appspot.com/.

También puedes usar una forma alternativa de la URL con versión appspot.com diseñada para evitar este problema si reemplazas los puntos que separan los componentes del subdominio con la string “-dot-”. En el ejemplo anterior, se podría acceder sin una advertencia del certificado en https://1-dot-latest-dot-your_app_id.appspot.com/.

El inicio y cierre de sesión de las Cuentas de Google siempre se realiza con una conexión segura y no se relaciona con la configuración de las URL de las aplicaciones.

Como se mencionó antes, las restricciones de seguridad aplican a los archivos estáticos y a los servlets. Esto incluye la garantía de transporte.

Nota: Google recomienda usar el protocolo HTTPS para enviar solicitudes a tu app. Google no emite certificados SSL para dominios de comodín doble alojados en appspot.com. Por lo tanto, con HTTPS debes usar la string “-dot-” en vez de “.” para separar los subdominios, como se muestra en los ejemplos que aparecen a continuación. Puedes usar un “.” simple con tu propio dominio personalizado o con las direcciones HTTP.

La lista de archivos de bienvenida

Cuando las URL de tu sitio representan rutas a archivos estáticos o JSP en tu WAR, suele ser una buena idea que las rutas a los directorios también hagan algo útil. Un usuario que visita la ruta de URL /help/accounts/password.jsp para obtener información sobre contraseñas podría intentar visitar /help/accounts/ y encontrar una página que presente la documentación del sistema de la cuenta. El descriptor de implementación puede especificar una lista de nombres de archivo que el servidor debe probar cuando el usuario accede a una ruta que representa un subdirectorio del WAR que no esté asignado de manera explícita a un servlet. El estándar de servlet llama a esto la “lista de archivos de bienvenida”.

Por ejemplo, si el usuario accede a la ruta de URL /help/accounts/, el siguiente elemento <welcome-file-list> en el descriptor de implementación le indica al servidor que debe verificar help/accounts/index.jsp y help/accounts/index.html antes de informar que la URL no existe:

    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
        <welcome-file>index.html</welcome-file>
    </welcome-file-list>

Filtros

Un filtro es una clase que actúa ante una solicitud, como un servlet, pero puede permitir que el procesamiento de la solicitud continúe con otros filtros o servlets. Un filtro puede llevar a cabo una tarea auxiliar, como registrar, realizar verificaciones de autenticación especializadas o anotar los objetos de solicitud o respuesta antes de llamar al servlet. Los filtros te permiten redactar tareas de procesamiento de solicitudes desde el descriptor de implementación.

Una clase de filtro implementa la interfaz javax.servlet.Filter, incluido el método doFilter(). Aquí hay una implementación de filtro simple que registra un mensaje y pasa el control a lo largo de la cadena, que puede incluir otros filtros o un servlet, como lo indica el descriptor de implementación:

package mysite.server;

import java.io.IOException;
import java.util.logging.Logger;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

public class LogFilterImpl implements Filter {

    private FilterConfig filterConfig;
    private static final Logger log = Logger.getLogger(LogFilterImpl.class.getName());

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
        throws IOException, ServletException {
        log.warning("Log filter processed a " + getFilterConfig().getInitParameter("logType")
            + " request");

        filterChain.doFilter(request, response);
    }

    public FilterConfig getFilterConfig() {
        return filterConfig;
    }

    public void init(FilterConfig filterConfig) {
        this.filterConfig = filterConfig;
    }

    public void destroy() {}

}

De manera similar a los servlets, puedes configurar un filtro en el descriptor de implementación si lo declaras con el elemento <filter> y, luego, lo asignas a un patrón de URL con el elemento <filter-mapping>. También puedes asignar filtros directamente a otros servlets.

El elemento <filter> contiene los elementos <filter-name>, <filter-class> y, de forma opcional, <init-param>.

    <filter>
        <filter-name>logSpecial</filter-name>
        <filter-class>mysite.server.LogFilterImpl</filter-class>
        <init-param>
            <param-name>logType</param-name>
            <param-value>special</param-value>
        </init-param>
    </filter>

El elemento <filter-mapping> contiene un elemento <filter-name> que coincide con el nombre de un filtro declarado. Además, puede contener un elemento <url-pattern> para aplicar el filtro a las URL o un elemento <servlet-name> que coincide con el nombre de un servlet declarado con el fin de aplicar el filtro todas las veces que se llama al servlet.

    <!-- Log for all URLs ending in ".special" -->
    <filter-mapping>
        <filter-name>logSpecial</filter-name>
        <url-pattern>*.special</url-pattern>
    </filter-mapping>

    <!-- Log for all URLs that use the "comingsoon" servlet -->
    <filter-mapping>
        <filter-name>logSpecial</filter-name>
        <servlet-name>comingsoon</servlet-name>
    </filter-mapping>

Controladores de errores

Puedes personalizar lo que el servidor envía al usuario cuando se produce un error mediante el descriptor de implementación. El servidor puede mostrar una ubicación de página alternativa cuando está por enviar un código de estado HTTP particular o cuando un servlet genera una excepción de Java específica.

El elemento <error-page> contiene un elemento <error-code> con un valor de código de error HTTP (como 500) o un elemento <exception-type> con el nombre de la clase de excepción esperada (como java.io.IOException). También contiene un elemento <location> con la ruta de URL del recurso para mostrar cuándo se produce el error.

    <error-page>
        <error-code>500</error-code>
        <location>/errors/servererror.jsp</location>
    </error-page>

Características de web.xml no compatibles

Las siguientes características de web.xml no son compatibles con App Engine:

  • App Engine es compatible con el elemento <load-on-startup> para las declaraciones de servlet. Sin embargo, la carga se produce en realidad durante la primera solicitud controlada por la instancia del servidor web, no antes.
  • Algunos elementos del descriptor de implementación pueden tener un nombre visible, una descripción y un ícono legibles para su uso en los IDE. App Engine no los usa y los ignora.
  • App Engine no es compatible con variables de entorno JNDI (<env-entry>).
  • App Engine no es compatible con recursos EJB (<resource-ref>).
  • No se admite la notificación de destrucción de servlets, contexto de servlet ni filtros.
  • El elemento <distributable> se ignora.
  • No se admite la programación de servlets con <run-at>.
¿Te ha resultado útil esta página? Enviar comentarios:

Enviar comentarios sobre...

Entorno estándar de App Engine para Java