在 servlet 过滤器中向请求添加 HTTP 标头
Posted
技术标签:
【中文标题】在 servlet 过滤器中向请求添加 HTTP 标头【英文标题】:Adding an HTTP Header to the request in a servlet filter 【发布时间】:2011-02-18 04:47:10 【问题描述】:我正在与现有的 servlet 集成,该 servlet 从 HTTP 标头中提取一些属性。基本上,我正在实现一个无法访问实际请求的接口,它只能访问 HTTP 标头的 k->v 映射。
我需要传入一个请求参数。计划是使用 servlet 过滤器从参数到标头值,但当然 HttpServletRequest 对象没有 addHeader() 方法。
有什么想法吗?
【问题讨论】:
【参考方案1】:扩展HttpServletRequestWrapper
,覆盖头部getter也返回参数:
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);
..并用它包装原始请求:
chain.doFilter(new AddParamsToHeader((HttpServletRequest) request), response);
也就是说,我个人认为这是个坏主意。而是让它直接访问参数或将参数传递给它。
【讨论】:
我认为这也不是一个好主意......问题是我只是一个小类集成到一个大型现有系统中。 有没有办法通过实际修改标题而不是覆盖 getHeader 方法来做到这一点?看起来更进一步的东西覆盖了我的 getHeader 方法。 唯一的方法是充当代理并创建一个全新的 HTTP 请求,并在java.net.URLConnection
的帮助下在相关 servlet 的 URL 上触发该请求,然后将其响应流回。效率不高。
很好的答案。只是一点点补充:有时也需要覆盖 getHeaders
(例如,当通过 Jersey 1.X 使用 JAX-RS 时)。
@miku 通过下面的 getHeaders 找到答案【参考方案2】:
您必须使用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);
根据您想要做什么,您可能需要实现包装器的其他方法,例如 getHeaderNames
。请注意,这是信任客户端并允许他们操作任何 HTTP 标头。您可能希望对它进行沙箱处理,并且只允许以这种方式修改某些标头值。
【讨论】:
有没有办法通过实际修改标题而不是覆盖 getHeader 方法来做到这一点?看起来更进一步的东西覆盖了我的 getHeader 方法。 您可能需要在 web.xml 中重新排序您的过滤器。让它成为链条中的最后一个。【参考方案3】:正如https://***.com/users/89391/miku 指出的那样,这将是一个完整的 ServletFilter 示例,它使用同样适用于 Jersey 的代码添加 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://***.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 sn-p:
<!-- 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>
【讨论】:
Http 标头不区分大小写,但您的 HeaderMapRequestWrapper 的实现并未考虑到这一点。以上是关于在 servlet 过滤器中向请求添加 HTTP 标头的主要内容,如果未能解决你的问题,请参考以下文章