【问题标题】:Adding an HTTP Header to the request in a servlet filter在 servlet 过滤器中向请求添加 HTTP 标头
【发布时间】:2011-02-18 04:47:10
【问题描述】:

我正在与现有的 servlet 集成,该 servlet 从 HTTP 标头中提取一些属性。基本上,我正在实现一个无法访问实际请求的接口,它只能访问 HTTP 标头的 k->v 映射。

我需要传入一个请求参数。计划是使用 servlet 过滤器从参数到标头值,但当然 HttpServletRequest 对象没有 addHeader() 方法。

有什么想法吗?

【问题讨论】:

    标签: java servlets jakarta-ee servlet-filters


    【解决方案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://stackoverflow.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://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 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 的实现并未考虑到这一点。
    猜你喜欢
    • 1970-01-01
    • 2023-04-04
    • 1970-01-01
    • 1970-01-01
    • 2021-06-09
    • 2017-12-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多