Filtros vs Interceptores

Errores en Web Escriptori: max-age

Emilio Ponce

Flujo Control Spring MVC

Antes de empezar...

  1. Spring consulta web.xml donde está definido el DispatcherServlet y le hace llegar la petición entrante.

  2. Spring empieza a ejecutar la cadena de Interceptores. Métodos preHandle.

  3. Pasa luego a controlador correspondiente.

  4. Ejecuta métodos postHandle de interceptores.

  5. Encuentra vista correspondiente con View Resolver, envía el modelo a la vista y la renderiza.

Cadena!

Filtros

e

Interceptores

Interceptores

  • Parte de Spring MVC

  • Intercepta una petición HTTP (req, res)

  • Orden de ejecución
    • respecto a flujo Spring MVC
      • preHandle: antes del controlador
      • postHandle: después del controlador pero antes de renderizar la vista
      • afterCompletion: después de renderizar la vista
    • Respecto a otros interceptores
      • Globales: siempre antes que los concretos (*)
      • Concretos: en el orden en el que han sido declarados en xml.

Uso

  • Login
  • Autenticación
  • Añadir cabeceras HTTP
  • Conversión imágenes
  • ...

Implementación

org.springframework.web.servlet.HandlerInterceptor

 

org.springframework.web.servlet.handler.HandlerInterceptorAdapter

Declaración

En contexto de Spring MVC (nombreAplicacion-servlet.xml):

Implementando la interfaz:

Extendiendo la clase abstracta:

<mvc:interceptors> 
        <mvc:interceptor>
            <mvc:mapping path="/**" />
            <bean id="profileInterceptor"
            class="cat.meteo.webescriptori.controller.ProfileInterceptor" />
        </mvc:interceptor>
</mvc:interceptors>

Filtros

  • Forman parte de la especificación de Servlets
  • Los ejecuta el propio contenedor
  • También en cadena
  • No son componentes de Spring
  • Intercepta una petición HTTP (tanto req. como res.)
  • Implementación típica: Wrapper de request y/o response

Implementación

Implementando la interfaz:

javax.servlet.Filter

Y sobreescribiendo método doFilter() que se ejecuta con cada petición 

Uso

Para tareas parecidas a los interceptores

Declaración

  • En Deployment Descriptor (web.xml)
<filter>
    <filter-name>AutenticacionFilter</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>

<filter-mapping>
    <filter-name>AutenticacionFilter</filter-name>
    <url-pattern>/usuarios/*</url-pattern>
</filter-mapping>
 <bean id="AutenticacionFilter" 
       class="cat.meteo.webescriptori.controller.AutenticacionFilter">
  • En applicationContext.xml

Filtros vs Interceptores

  • Interceptores son parte de especificación Spring MVC
  • Filtros son parte de la especificación Servlet
  • En un interceptor tienes acceso a modelAndView, HttpServletRequest y HttpServletResponse
  • En un Filtro sólo a HttpServletRequest y HttpServletResponse

Filtros vs Interceptores

  • Si siempre vamos a manipular el contenido de la request/response, mejor usar un filtro
     
  • Si se quiere ejecutar una acción específica para una request concreta, es mejor usar un Interceptor (granularidad)

Recomendaciones de uso

Filtros vs Interceptores

Cuando se ejecutan?

  • El interceptor lo ejecuta Spring
    El filtro lo ejecuta el contenedor de servlets (Tomcat)
     
  • Interceptor dispone de tres puntos de ejecución
    Filtros de do

Request

I1

I2

I3

I3

 

I2

I1

preHandle

preHandle

preHandle

postHandle

postHandle

postHandle

Controller

D
I
S
P
A
T

C

H

E

R

S

E

R

V

L

E

T

Aplicación Web

TOMCAT

C

H

A

I

N

Spring

Filter
Request

Chain

Chain

Service ...

Response

Filter
Response

Web Escriptori

Gestión de errores: max-age

OBJETIVO

Aplicación fija max-age para Varnish:

  • Página OK                600 seg max-age
  • Página Error             120  seg max-age

Cómo detectar un error de componente dentro de una sección?

PROBLEMA

SOLUCIÓN

Código de error dentro de HTML de respuesta, para que un FILTRO lo pueda detectar.

<filter>
    <filter-name>MaxAgeFilter</filter-name>
    <!-- delega en el MaxAgeFilter definit al context de l'aplicació -->
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>

<!-- especifiquem per a que urls s'executa filtre que baixa MaxAge -->
<filter-mapping>
    <filter-name>MaxAgeFilter</filter-name>
    <url-pattern>/</url-pattern>
    <url-pattern>/observacions/*</url-pattern>
    <url-pattern>/prediccio/*</url-pattern>
</filter-mapping>

web.xml

 <mvc:interceptor>
            <mvc:mapping path="/**" />
            <bean id="webContentInterceptor" 
                  class="org.springframework.web.servlet.mvc.WebContentInterceptor">
                <property name="cacheSeconds" value="600" />
                <property name="useExpiresHeader" value="false" />
                <property name="useCacheControlHeader" value="true" />
                <property name="useCacheControlNoStore" value="false" />
                <property name="cacheMappings">
                    <props>
                        <prop key="/*">600</prop>                        
                    </props>
                </property>
            </bean>
</mvc:interceptor>

webescriptori-servlet.xml

<!-- Afegim filtre al Context -->
<bean id="MaxAgeFilter" class="cat.meteo.webescriptori.controller.MaxAgeFilter">
    <property name="errorCacheTime" value="120"/>
    <property name="cadenaError" value="(╯°□°)╯︵ ┻━┻ error!"/>
</bean>

applicationContext.xml

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!--(╯°□°)╯︵ ┻━┻ error!-->
<div class="errorpage">
    <h1>Uups! S'ha produït un error</h1>
    <p>En aquests moments no podem mostrar la informació 
    sol·licitada. Torna-ho a intentar d'aquí a uns minuts.</p>
    <p>Disculpa les molèsties.</p>
</div>

errorcomponent.jsp

// FILTER
 
public class MaxAgeFilter implements Filter {
...
@Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
            throws IOException, ServletException {

        // fiquem response a un wrapper i apliquem filtre per poder extreure html
        HttpServletResponse response = (HttpServletResponse) res;
        MyHttpServletResponseWrapper wrapper = new MyHttpServletResponseWrapper(response);

        // ejecuta filtro que almacena respuesta en wrapper, que tiene el método 
        // toString sobreescrito
        chain.doFilter(req, wrapper);

        // si a la resposta hi ha algun error canviem capçalera MaxAge
        String contingut = wrapper.toString();
        if (contingut.contains(cadenaError)) {
            response.setHeader("Cache-Control", "max-age=" + errorCacheTime);
        }

        // escribimos output de res en navegador (renderizamos con PrintWriter original)
        try (PrintWriter out = response.getWriter()) {
            out.println(contingut);
        } catch (IOException ex) {
            log.error("error a filtre MaxAgeFilter", ex);
        }
    }
}

MaxAgeFilter.java

class MyHttpServletResponseWrapper extends HttpServletResponseWrapper {

    private final StringWriter sw = new StringWriter();

    ...

    @Override
    public PrintWriter getWriter() throws IOException {
        // sobreescribimos printWriter para que guarde en String 
        // y no en ouputStream (no renderiza! en navegador)
        return new PrintWriter(sw);
    }

    ...

    @Override
    public String toString() {
        return sw.toString();
    }
}

MaxAgeFilter.java

Gracias

Made with Slides.com