2010-05-11 11 views
28

Estoy integrando con un servlet existente que extrae algunas propiedades del encabezado HTTP. Básicamente, estoy implementando una interfaz que no tiene acceso a la solicitud real, solo tiene acceso a un mapa de k-> v para los encabezados HTTP.Agregar un encabezado HTTP a la solicitud en un filtro de servlet

Necesito pasar un parámetro de solicitud. El plan es usar un filtro de servlet para pasar de un parámetro a un valor de encabezado pero, por supuesto, el objeto HttpServletRequest no tiene un método addHeader().

¿Alguna idea?

Respuesta

32

Extender HttpServletRequestWrapper, anular los captadores de cabecera para devolver los parámetros, así:

public class AddParamsToHeader extends HttpServletRequestWrapper { 
    public AddParamsToHeader(HttpServletRequest request) { 
     super(request); 
    } 

    public String getHeader(String name) { 
     String header = super.getHeader(name); 
     return (header != null) ? header : super.getParameter(name); // Note: you can't use getParameterValues() here. 
    } 

    public Enumeration getHeaderNames() { 
     List<String> names = Collections.list(super.getHeaderNames()); 
     names.addAll(Collections.list(super.getParameterNames())); 
     return Collections.enumeration(names); 
    } 
} 

..y envolver la solicitud original con ella:

chain.doFilter(new AddParamsToHeader((HttpServletRequest) request), response); 

Dicho esto, yo personalmente encuentra esto una mala idea. Mejor déle acceso directo a los parámetros o pase los parámetros a él.

+1

Creo que no es una gran idea, ya sea ... el tema es que soy sólo una pequeña clase integrar en un sistema existente grande. – Mason

+0

¿Hay alguna manera de hacerlo modificando los encabezados en lugar de anular el método getHeader? Parece que algo más adelante anula mi método getHeader. – Mason

+2

La única forma sería actuar en representación de un proxy y crear una solicitud HTTP completamente nueva e iniciarla en la URL del servlet en cuestión con la ayuda de 'java.net.URLConnection' y luego volver a transmitir su respuesta. No es realmente eficiente. – BalusC

13

Vas a tener que utilizar un HttpServletRequestWrapper:

public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain) throws IOException, ServletException { 
    final HttpServletRequest httpRequest = (HttpServletRequest) request; 
    HttpServletRequestWrapper wrapper = new HttpServletRequestWrapper(httpRequest) { 
     @Override 
     public String getHeader(String name) { 
      final String value = request.getParameter(name); 
      if (value != null) { 
       return value; 
      } 
      return super.getHeader(name); 
     } 
    }; 
    chain.doFilter(wrapper, response); 
} 

Dependiendo de lo que quiere hacer puede que tenga que aplicar otros métodos de la envoltura como getHeaderNames por ejemplo. Solo tenga en cuenta que esto es confiar en el cliente y permitirle manipular cualquier encabezado HTTP. Es posible que desee guardarlos en una zona de pruebas y permitir que ciertos valores de encabezado se modifiquen de esta manera.

+1

¿Hay alguna manera de hacerlo modificando los encabezados en lugar de anular el getHeader? ¿método? Parece que algo más adelante anula mi método getHeader. – Mason

+0

Probablemente necesite volver a ordenar sus filtros en web.xml. Haz que este sea el último en la cadena. – laz

12

como https://stackoverflow.com/users/89391/miku señaló que este sería un ejemplo completo de ServletFilter que utiliza el código que también funciona para Jersey para agregar el encabezado remote_addr.

package com.bitplan.smartCRM.web; 

import java.io.IOException; 
import java.util.Collections; 
import java.util.Enumeration; 
import java.util.HashMap; 
import java.util.List; 
import java.util.Map; 

import javax.servlet.Filter; 
import javax.servlet.FilterChain; 
import javax.servlet.FilterConfig; 
import javax.servlet.ServletException; 
import javax.servlet.ServletRequest; 
import javax.servlet.ServletResponse; 
import javax.servlet.http.HttpServletRequest; 
import javax.servlet.http.HttpServletRequestWrapper; 

/** 
* 
* @author wf 
* 
*/ 
public class RemoteAddrFilter implements Filter { 

    @Override 
    public void destroy() { 

    } 

    @Override 
    public void doFilter(ServletRequest request, ServletResponse response, 
      FilterChain chain) throws IOException, ServletException { 
     HttpServletRequest req = (HttpServletRequest) request; 
     HeaderMapRequestWrapper requestWrapper = new HeaderMapRequestWrapper(req); 
     String remote_addr = request.getRemoteAddr(); 
     requestWrapper.addHeader("remote_addr", remote_addr); 
     chain.doFilter(requestWrapper, response); // Goes to default servlet. 
    } 

    @Override 
    public void init(FilterConfig filterConfig) throws ServletException { 

    } 

    // https://stackoverflow.com/questions/2811769/adding-an-http-header-to-the-request-in-a-servlet-filter 
    // http://sandeepmore.com/blog/2010/06/12/modifying-http-headers-using-java/ 
    // http://bijubnair.blogspot.de/2008/12/adding-header-information-to-existing.html 
    /** 
    * allow adding additional header entries to a request 
    * 
    * @author wf 
    * 
    */ 
    public class HeaderMapRequestWrapper extends HttpServletRequestWrapper { 
     /** 
     * construct a wrapper for this request 
     * 
     * @param request 
     */ 
     public HeaderMapRequestWrapper(HttpServletRequest request) { 
      super(request); 
     } 

     private Map<String, String> headerMap = new HashMap<String, String>(); 

     /** 
     * add a header with given name and value 
     * 
     * @param name 
     * @param value 
     */ 
     public void addHeader(String name, String value) { 
      headerMap.put(name, value); 
     } 

     @Override 
     public String getHeader(String name) { 
      String headerValue = super.getHeader(name); 
      if (headerMap.containsKey(name)) { 
       headerValue = headerMap.get(name); 
      } 
      return headerValue; 
     } 

     /** 
     * get the Header names 
     */ 
     @Override 
     public Enumeration<String> getHeaderNames() { 
      List<String> names = Collections.list(super.getHeaderNames()); 
      for (String name : headerMap.keySet()) { 
       names.add(name); 
      } 
      return Collections.enumeration(names); 
     } 

     @Override 
     public Enumeration<String> getHeaders(String name) { 
      List<String> values = Collections.list(super.getHeaders(name)); 
      if (headerMap.containsKey(name)) { 
       values.add(headerMap.get(name)); 
      } 
      return Collections.enumeration(values); 
     } 

    } 

} 

Web.xml fragmento:

<!-- first filter adds remote addr header --> 
<filter> 
    <filter-name>remoteAddrfilter</filter-name> 
    <filter-class>com.bitplan.smartCRM.web.RemoteAddrFilter</filter-class> 
</filter> 
<filter-mapping> 
    <filter-name>remoteAddrfilter</filter-name> 
    <url-pattern>/*</url-pattern> 
</filter-mapping> 
Cuestiones relacionadas