修改request中header的值

      在java web开发中,我们有时候会遇到需要修改request中请求值的问题,虽然这个不是特别常见。初看这是一个简单的问题,因为我们能通过HttpServletRequest对象拿到我们需要的所有关于当前这个请求的所有信息,想当然的也就可以修改所以这些信息。可实际情况是HttpServletReques中很多的属性只有getter方法,而没有setter方法,也就是说我们不可以修改他们。

        记得第一次遇到这种问题还是初学编程的时候,最近又遇到这个问题,就记录一下。最近遇到的是在spring mvc中,使用@RequestBody注解把requestBody中的json映射到java的object。我们知道对于spring mvc来说,这样使用的时候需要在请求的header里面表明conten-type为application/json。如果完全是自己开发的系统,没有问题加上就是,但是当和第三方合作的时候,请求的发起方式就不是我们能控制住的了。现在的问题是如果使用spring mvc的这种开发模式,必须要在请求的header中设置content-type为application/json,但是第三方又不方便设置。所以只能在所有针对第三方的API中进行特殊处理。

       sping mvc是基于servlet的,我们只要在请求进入servlet之前在header中设置content-type为application/json就ok了,所以理想的修改方式就是加入一个filter。现在就到了关键的问题:怎么修改请求的header值。答案是利用HttpServletRequestWrapper类。

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        chain.doFilter(new CustomeizedRequest((HttpServletRequest) request), response);
    }

    private class CustomeizedRequest extends HttpServletRequestWrapper {

        public CustomeizedRequest(HttpServletRequest request) {
            super(request);
        }

        @Override
        public Enumeration<String> getHeaders(String name) {
            if (null != name && name.equals("Content-Type")) {
                return new Enumeration<String>() {
                    private boolean hasGetted = false;

                    @Override
                    public String nextElement() {
                        if (hasGetted) {
                            throw new NoSuchElementException();
                        } else {
                            hasGetted = true;
                            return "application/json;charset=utf-8";
                        }
                    }

                    @Override
                    public boolean hasMoreElements() {
                        return !hasGetted;
                    }
                };
            }
            return super.getHeaders(name);
        }
    }

       demo中只重写了getHeaders方法,实际上严谨的做法是getHeader(String name)方法也要被重写。实质上我们还是没有改变header中的值的能力,但是我们重写了getHeaders方法,当发现是我们的Content-Type字段时,只要返回我们想要设置的值就OK了。同理我们可以任意发挥,根据实际的情况去重写相应的方法。

      说一下我在这里遇到的一个问题,在开发过程中使用的maven加jetty插件,运行起来没有问题。但是测试和生产环境用的是tomcat,上了测试环境发现没有效果。第一感觉是不同的容器中Content-Type的大小写或写法不一样。打了一个log继续测试,发现tomcat好像根本没进入我的getHeaders方法,就开始怀疑tomcat和jetty的某些实现不一致,各种查找没有结果。最后在本地换成tomcat来debug,竟然进入了重写的getHeaders方法,再一看name的值是:content-type。粗心把log打错位置了。。。,刚开始猜想的是对的。

       所以这里的name.equals("Content-Type")就要考虑大小写和不同写法的因素了(比如contenttype或ContentType)。

后来想了一下之所以会出现这个失误有两个原因:

  1.  粗心 log打错位置
  2.  自身对于容器不熟悉,而且之前遇到过tomcat和jetty对于某些请求作不同处理的情况,所以就找错了方向。

        记得第一次遇到这种问题还是初学编程的时候,最近又遇到这个问题,就记录一下。最近遇到的是在spring mvc中,使用@RequestBody注解把requestBody中的json映射到java的object。我们知道对于spring mvc来说,这样使用的时候需要在请求的header里面表明conten-type为application/json。如果完全是自己开发的系统,没有问题加上就是,但是当和第三方合作的时候,请求的发起方式就不是我们能控制住的了。现在的问题是如果使用spring mvc的这种开发模式,必须要在请求的header中设置content-type为application/json,但是第三方又不方便设置。所以只能在所有针对第三方的API中进行特殊处理。

       sping mvc是基于servlet的,我们只要在请求进入servlet之前在header中设置content-type为application/json就ok了,所以理想的修改方式就是加入一个filter。现在就到了关键的问题:怎么修改请求的header值。答案是利用HttpServletRequestWrapper类。

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        chain.doFilter(new CustomeizedRequest((HttpServletRequest) request), response);
    }

    private class CustomeizedRequest extends HttpServletRequestWrapper {

        public CustomeizedRequest(HttpServletRequest request) {
            super(request);
        }

        @Override
        public Enumeration<String> getHeaders(String name) {
            if (null != name && name.equals("Content-Type")) {
                return new Enumeration<String>() {
                    private boolean hasGetted = false;

                    @Override
                    public String nextElement() {
                        if (hasGetted) {
                            throw new NoSuchElementException();
                        } else {
                            hasGetted = true;
                            return "application/json;charset=utf-8";
                        }
                    }

                    @Override
                    public boolean hasMoreElements() {
                        return !hasGetted;
                    }
                };
            }
            return super.getHeaders(name);
        }
    }

       demo中只重写了getHeaders方法,实际上严谨的做法是getHeader(String name)方法也要被重写。实质上我们还是没有改变header中的值的能力,但是我们重写了getHeaders方法,当发现是我们的Content-Type字段时,只要返回我们想要设置的值就OK了。同理我们可以任意发挥,根据实际的情况去重写相应的方法。

      说一下我在这里遇到的一个问题,在开发过程中使用的maven加jetty插件,运行起来没有问题。但是测试和生产环境用的是tomcat,上了测试环境发现没有效果。第一感觉是不同的容器中Content-Type的大小写或写法不一样。打了一个log继续测试,发现tomcat好像根本没进入我的getHeaders方法,就开始怀疑tomcat和jetty的某些实现不一致,各种查找没有结果。最后在本地换成tomcat来debug,竟然进入了重写的getHeaders方法,再一看name的值是:content-type。粗心把log打错位置了。。。,刚开始猜想的是对的。

       所以这里的name.equals("Content-Type")就要考虑大小写和不同写法的因素了(比如contenttype或ContentType)。

后来想了一下之所以会出现这个失误有两个原因:

  1.  粗心 log打错位置
  2.  自身对于容器不熟悉,而且之前遇到过tomcat和jetty对于某些请求作不同处理的情况,所以就找错了方向。

        记得第一次遇到这种问题还是初学编程的时候,最近又遇到这个问题,就记录一下。最近遇到的是在spring mvc中,使用@RequestBody注解把requestBody中的json映射到java的object。我们知道对于spring mvc来说,这样使用的时候需要在请求的header里面表明conten-type为application/json。如果完全是自己开发的系统,没有问题加上就是,但是当和第三方合作的时候,请求的发起方式就不是我们能控制住的了。现在的问题是如果使用spring mvc的这种开发模式,必须要在请求的header中设置content-type为application/json,但是第三方又不方便设置。所以只能在所有针对第三方的API中进行特殊处理。

       sping mvc是基于servlet的,我们只要在请求进入servlet之前在header中设置content-type为application/json就ok了,所以理想的修改方式就是加入一个filter。现在就到了关键的问题:怎么修改请求的header值。答案是利用HttpServletRequestWrapper类。

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        chain.doFilter(new CustomeizedRequest((HttpServletRequest) request), response);
    }

    private class CustomeizedRequest extends HttpServletRequestWrapper {

        public CustomeizedRequest(HttpServletRequest request) {
            super(request);
        }

        @Override
        public Enumeration<String> getHeaders(String name) {
            if (null != name && name.equals("Content-Type")) {
                return new Enumeration<String>() {
                    private boolean hasGetted = false;

                    @Override
                    public String nextElement() {
                        if (hasGetted) {
                            throw new NoSuchElementException();
                        } else {
                            hasGetted = true;
                            return "application/json;charset=utf-8";
                        }
                    }

                    @Override
                    public boolean hasMoreElements() {
                        return !hasGetted;
                    }
                };
            }
            return super.getHeaders(name);
        }
    }

       demo中只重写了getHeaders方法,实际上严谨的做法是getHeader(String name)方法也要被重写。实质上我们还是没有改变header中的值的能力,但是我们重写了getHeaders方法,当发现是我们的Content-Type字段时,只要返回我们想要设置的值就OK了。同理我们可以任意发挥,根据实际的情况去重写相应的方法。

      说一下我在这里遇到的一个问题,在开发过程中使用的maven加jetty插件,运行起来没有问题。但是测试和生产环境用的是tomcat,上了测试环境发现没有效果。第一感觉是不同的容器中Content-Type的大小写或写法不一样。打了一个log继续测试,发现tomcat好像根本没进入我的getHeaders方法,就开始怀疑tomcat和jetty的某些实现不一致,各种查找没有结果。最后在本地换成tomcat来debug,竟然进入了重写的getHeaders方法,再一看name的值是:content-type。粗心把log打错位置了。。。,刚开始猜想的是对的。

       所以这里的name.equals("Content-Type")就要考虑大小写和不同写法的因素了(比如contenttype或ContentType)。

后来想了一下之所以会出现这个失误有两个原因:

  1.  粗心 log打错位置
  2.  自身对于容器不熟悉,而且之前遇到过tomcat和jetty对于某些请求作不同处理的情况,所以就找错了方向。

猜你喜欢

转载自vinson00.iteye.com/blog/2237482