2010-05-11 14 views
28

Sto integrando con un servlet esistente che estrae alcune proprietà dall'intestazione HTTP. Fondamentalmente, sto implementando un'interfaccia che non ha accesso alla richiesta effettiva, ha solo accesso a una mappa di k-> v per le intestazioni HTTP.Aggiunta di un'intestazione HTTP alla richiesta in un filtro servlet

Ho bisogno di passare un parametro di richiesta. Il piano consiste nell'utilizzare un filtro servlet per passare dal parametro al valore dell'intestazione, ma ovviamente l'oggetto HttpServletRequest non ha un metodo addHeader().

Qualche idea?

risposta

32

Estendere HttpServletRequestWrapper, ignorare i getter di intestazione per riportare i parametri così:

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); 
    } 
} 

..e avvolgere la richiesta originale con esso:

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

Detto questo, io personalmente trova questa una cattiva idea Piuttosto dargli accesso diretto ai parametri o passare i parametri ad esso.

+1

penso che non sia una grande idea o ... il problema è che sono solo una piccola classe che integra in un grande sistema esistente. – Mason

+0

C'è un modo per farlo modificando effettivamente le intestazioni invece di sovrascrivere il metodo getHeader? Sembra che qualcosa di più in basso sovrascriva il metodo getHeader. – Mason

+2

L'unico modo sarebbe quello di agire per un proxy e creare una richiesta HTTP completamente nuova e attivarla sull'URL del servlet in questione con l'aiuto di 'java.net.URLConnection' e quindi inviare nuovamente la sua risposta. Non proprio efficiente. – BalusC

13

Dovrete usare 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); 
} 

A seconda di cosa si vuole fare, potrebbe essere necessario implementare altri metodi di wrapper come getHeaderNames per esempio. Basta essere consapevoli del fatto che questo si fida del client e consente loro di manipolare qualsiasi intestazione HTTP. Si consiglia di eseguire il sandbox e solo consentire a determinati valori di intestazione di essere modificati in questo modo.

+1

C'è un modo per farlo modificando effettivamente le intestazioni invece di sovrascrivere l'getHeader metodo? Sembra che qualcosa di più in basso sovrascriva il metodo getHeader. – Mason

+0

Quindi è necessario riordinare i filtri in web.xml. Rendi questo l'ultimo della catena. – laz

12

come https://stackoverflow.com/users/89391/miku ha sottolineato che questo sarebbe un esempio ServletFilter completo che utilizza il codice che funziona anche per Jersey per aggiungere l'intestazione 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 frammento:

<!-- 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> 
Problemi correlati