Filtros vs Interceptores
Errores en Web Escriptori: max-age
Emilio Ponce
Flujo Control Spring MVC
Antes de empezar...
-
Spring consulta web.xml donde está definido el DispatcherServlet y le hace llegar la petición entrante.
-
Spring empieza a ejecutar la cadena de Interceptores. Métodos preHandle.
-
Pasa luego a controlador correspondiente.
-
Ejecuta métodos postHandle de interceptores.
-
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.
-
respecto a flujo Spring MVC
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
Interceptors, Filtres
By Emilio Ponce
Interceptors, Filtres
Spring Interceptors, Servlet Filters. Tractament errors nova aplicació web
- 1,023