HttpServletRequestWrapper的使用

老大给了一个很实际的需求:有段程序,使用Http的方式与合作商交互,而且是明文传输数据。我方的代码已经打包放在服务器上运行了很长时间,这时合作商突然要求修改数据传输的方式,要求加密后再传输,而我方的原有的代码不能改变,以防止引发其它问题。 
问:如何在不修改我方现有的代码的前提下,满足合作商的要求? 

可能大家都想到了,只要加上一个过滤器Filter不就可以了吗?事实就是这样的,采用Filter+HttpServletRequestWrapper就可以解决这个问题。 
首先:在filter中拦截到加密后的请求,将参数解密,然后组装成一个新的明文请求串。 
然后:重写HttpServletRequestWrapper中的getInputStream()方法,让其返回过滤器解析后的明文串即可。 

具体代码解释如下。 

首先我写了两个一摸一样的servlet,一个用来直接接收合作商的明文请求并打印;一个用来接收Filter处理后的合作商的请求并打印(Filter中将合作商加密后的参数解密再传给这个Servlet)。

Java代码  收藏代码
  1. @WebServlet("/SiServlet")  
  2. public class SiServlet extends HttpServlet {  
  3.     private static final long serialVersionUID = 1L;  
  4.   
  5.     /** 
  6.      * @see HttpServlet#HttpServlet() 
  7.      */  
  8.     public SiServlet() {  
  9.         super();  
  10.     }  
  11.   
  12.     /** 
  13.      * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse 
  14.      *      response) 
  15.      */  
  16.     protected void doGet(HttpServletRequest request,  
  17.             HttpServletResponse response) throws ServletException, IOException {  
  18.         this.doPost(request, response);  
  19.     }  
  20.   
  21.     /** 
  22.      * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse 
  23.      *      response) 
  24.      *  
  25.      */  
  26.     protected void doPost(HttpServletRequest request,  
  27.             HttpServletResponse response) throws ServletException, IOException {  
  28.         String bizBindMsg = IOUtils.toString(request.getInputStream(), "UTF-8");  
  29.         bizBindMsg = URLDecoder.decode(bizBindMsg.toString(), "UTF-8");  
  30.         System.out.println("SiServlet接收到请求为: " + bizBindMsg);  
  31.   
  32.         response.getWriter().write("==========success=========");  
  33.     }  
  34. }  
Java代码  收藏代码
  1. @WebServlet("/SiServletNormal")  
  2. public class SiServletNormal extends HttpServlet {  
  3.     private static final long serialVersionUID = 1L;  
  4.   
  5.     /** 
  6.      * @see HttpServlet#HttpServlet() 
  7.      */  
  8.     public SiServletNormal() {  
  9.         super();  
  10.     }  
  11.   
  12.     /** 
  13.      * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse 
  14.      *      response) 
  15.      */  
  16.     protected void doGet(HttpServletRequest request,  
  17.             HttpServletResponse response) throws ServletException, IOException {  
  18.         this.doPost(request, response);  
  19.     }  
  20.   
  21.     /** 
  22.      * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse 
  23.      *      response) 
  24.      *  
  25.      */  
  26.     protected void doPost(HttpServletRequest request,  
  27.             HttpServletResponse response) throws ServletException, IOException {  
  28.         String bizBindMsg = IOUtils.toString(request.getInputStream(), "UTF-8");  
  29.         bizBindMsg = URLDecoder.decode(bizBindMsg.toString(), "UTF-8");  
  30.         System.out.println("SiServletNormal接收到请求为: " + bizBindMsg);  
  31.   
  32.         response.getWriter()  
  33.                 .write("==========SiServletNormal Success=========");  
  34.     }  
  35. }  



然后我使用HttpClient模拟了一下合作商发送明文和密文请求的过程,加密使用Base64简单模拟一下。 

Java代码  收藏代码
  1. public class AdcClient {  
  2.     private HttpPost httpPost = null;  
  3.     private HttpClient client = null;  
  4.     private List<NameValuePair> pairs = null;  
  5.   
  6.     public AdcClient() {  
  7.         httpPost = new HttpPost("http://localhost:8080/filtertest/SiServlet");  
  8.         client = new DefaultHttpClient();  
  9.     }  
  10.   
  11.     /** 
  12.      * 发送明文消息 
  13.      *  
  14.      */  
  15.     public void sendMsg() {  
  16.   
  17.         try {  
  18.             httpPost = new HttpPost(  
  19.                     "http://localhost:8080/filtertest/SiServletNormal");  
  20.   
  21.             pairs = new ArrayList<NameValuePair>();  
  22.             pairs.add(new BasicNameValuePair(("param1"), "obama没加密"));  
  23.             pairs.add(new BasicNameValuePair(("param2"), "男没加密"));  
  24.             pairs.add(new BasicNameValuePair(("param3"), "汉没加密"));  
  25.             pairs.add(new BasicNameValuePair(("param4"), "山东没加密"));  
  26.   
  27.             httpPost.setEntity(new UrlEncodedFormEntity(pairs, "UTF-8"));  
  28.             // httpPost.setHeader("Cookie", "TOKEN=1234567890");  
  29.             HttpResponse response = client.execute(httpPost);  
  30.   
  31.             HttpEntity entity = response.getEntity();  
  32.             BufferedReader br = new BufferedReader(new InputStreamReader(  
  33.                     entity.getContent()));  
  34.             String line = null;  
  35.             StringBuffer result = new StringBuffer();  
  36.             while ((line = br.readLine()) != null) {  
  37.                 result.append(line);  
  38.                 line = br.readLine();  
  39.             }  
  40.   
  41.             System.out.println("来自SiServletNormal的响应为:" + result.toString());  
  42.         } catch (UnsupportedEncodingException e) {  
  43.             e.printStackTrace();  
  44.         } catch (ClientProtocolException e) {  
  45.             e.printStackTrace();  
  46.         } catch (IOException e) {  
  47.             e.printStackTrace();  
  48.         }  
  49.     }  
  50.   
  51.     /** 
  52.      * 发送加密后的消息 
  53.      */  
  54.     public void sendEncryptMsg() {  
  55.         try {  
  56.             pairs = new ArrayList<NameValuePair>();  
  57.             pairs.add(new BasicNameValuePair(("param1"), Base64EnDecrypt  
  58.                     .base64Encode("obama")));  
  59.             pairs.add(new BasicNameValuePair(("param2"), Base64EnDecrypt  
  60.                     .base64Encode("男")));  
  61.             pairs.add(new BasicNameValuePair(("param3"), Base64EnDecrypt  
  62.                     .base64Encode("汉")));  
  63.             pairs.add(new BasicNameValuePair(("param4"), Base64EnDecrypt  
  64.                     .base64Encode("山东")));  
  65.   
  66.             HttpEntity reqEntity = new UrlEncodedFormEntity(pairs, "UTF-8");  
  67.             httpPost.setEntity(reqEntity);  
  68.             // httpPost.setHeader("Cookie", "TOKEN=1234567890");  
  69.             HttpResponse response = client.execute(httpPost);  
  70.   
  71.             /** 
  72.              * 获取响应信息 
  73.              */  
  74.             HttpEntity entity = response.getEntity();  
  75.             BufferedReader br = new BufferedReader(new InputStreamReader(  
  76.                     entity.getContent()));  
  77.             String line = null;  
  78.             StringBuffer result = new StringBuffer();  
  79.             while ((line = br.readLine()) != null) {  
  80.                 result.append(line);  
  81.                 line = br.readLine();  
  82.             }  
  83.   
  84.             System.out.println("来自SiServlet的响应为:" + result.toString());  
  85.         } catch (UnsupportedEncodingException e) {  
  86.             e.printStackTrace();  
  87.         } catch (ClientProtocolException e) {  
  88.             e.printStackTrace();  
  89.         } catch (IOException e) {  
  90.             e.printStackTrace();  
  91.         }  
  92.     }  
  93.   
  94.     /** 
  95.      * @param args 
  96.      * @throws UnsupportedEncodingException 
  97.      */  
  98.     public static void main(String[] args) throws UnsupportedEncodingException {  
  99.         new AdcClient().sendMsg();  
  100.   
  101.         new AdcClient().sendEncryptMsg();  
  102.     }  
  103. }  


重点是下面的这个HttpServletRequestWrapper,我重写了它的getInputStream()方法,这个方法返回包含明文的ServletInputStream

Java代码  收藏代码
  1. public class MyRequestWrapper extends HttpServletRequestWrapper {  
  2.     private HttpServletRequest request;  
  3.   
  4.     public MyRequestWrapper(HttpServletRequest request) {  
  5.         super(request);  
  6.         this.request = request;  
  7.     }  
  8.   
  9.     /** 
  10.      * 先解密,获取明文;然后将明文转化为字节数组;然后再去读取字节数组中的内容 
  11.      */  
  12.     @Override  
  13.     public ServletInputStream getInputStream() {  
  14.         String bizBindMsg = null;  
  15.         ServletInputStream stream = null;  
  16.   
  17.         try {  
  18.             stream = request.getInputStream();  
  19.             bizBindMsg = IOUtils.toString(stream, "UTF-8");  
  20.         } catch (IOException e) {  
  21.             e.printStackTrace();  
  22.         }  
  23.         try {  
  24.             bizBindMsg = URLDecoder.decode(bizBindMsg.toString(), "UTF-8");  
  25.         } catch (UnsupportedEncodingException e) {  
  26.             e.printStackTrace();  
  27.         }  
  28.         System.out.println("MyRequestWrapper接收到的请求为: " + bizBindMsg);  
  29.   
  30.         /** 
  31.          * 获取加密的值进行解密 
  32.          */  
  33.         final StringBuffer reqStr = new StringBuffer();  
  34.         reqStr.append("param1=").append(  
  35.                 Base64EnDecrypt.base64Decode(bizBindMsg.substring(  
  36.                         bizBindMsg.indexOf("param1=") + 7,  
  37.                         bizBindMsg.indexOf("param2="))));  
  38.         reqStr.append("&");  
  39.         reqStr.append("param2=").append(  
  40.                 Base64EnDecrypt.base64Decode(bizBindMsg.substring(  
  41.                         bizBindMsg.indexOf("param2=") + 7,  
  42.                         bizBindMsg.indexOf("param3="))));  
  43.         reqStr.append("&");  
  44.         reqStr.append("param3=").append(  
  45.                 Base64EnDecrypt.base64Decode(bizBindMsg.substring(  
  46.                         bizBindMsg.indexOf("param3=") + 7,  
  47.                         bizBindMsg.indexOf("param4="))));  
  48.         reqStr.append("&");  
  49.         reqStr.append("param4=").append(  
  50.                 Base64EnDecrypt.base64Decode(bizBindMsg.substring(bizBindMsg  
  51.                         .indexOf("param4=") + 7)));  
  52.   
  53.         System.out.println("********MyRequestWrapper接收到的解密后的请求为*********");  
  54.         System.out.println(reqStr.toString());  
  55.   
  56.         /** 
  57.          * 将解密后的明文串放到buffer数组中 
  58.          */  
  59.         byte[] buffer = null;  
  60.         try {  
  61.             buffer = reqStr.toString().getBytes("UTF-8");  
  62.         } catch (UnsupportedEncodingException e) {  
  63.             e.printStackTrace();  
  64.         }  
  65.         final ByteArrayInputStream bais = new ByteArrayInputStream(buffer);  
  66.   
  67.         ServletInputStream newStream = new ServletInputStream() {  
  68.   
  69.             @Override  
  70.             public int read() throws IOException {  
  71.                 return bais.read();  
  72.             }  
  73.         };  
  74.         return newStream;  
  75.     }  
  76. }  


最后是简单的Filter,在这里将加密后的ServletRequest重新包装,交给SiServlet进行处理

Java代码  收藏代码
  1. public class EncryptFilter implements Filter {  
  2.   
  3.     @Override  
  4.     public void destroy() {  
  5.     }  
  6.   
  7.     @Override  
  8.     public void doFilter(ServletRequest request, ServletResponse response,  
  9.             FilterChain chain) throws IOException, ServletException {  
  10.   
  11.         chain.doFilter(new MyRequestWrapper((HttpServletRequest) request),  
  12.                 response);  
  13.     }  
  14.   
  15.     @Override  
  16.     public void init(FilterConfig arg0) throws ServletException {  
  17.   
  18.     }  
  19.   
  20. }  


我的web.xml中是这样配置的 

Java代码  收藏代码
  1. <filter>  
  2.     <filter-name>encryptFilter</filter-name>  
  3.     <filter-class>com.test.filter.EncryptFilter</filter-class>  
  4.   </filter>  
  5.   <filter-mapping>  
  6.     <filter-name>encryptFilter</filter-name>  
  7.     <url-pattern>/SiServlet</url-pattern>  
  8.   </filter-mapping>  


确保过滤器entyptFilter只拦截到SiServlet的请求即可。 

运行AdcClient,可以看到下面的结果 


这里的重点是MyRequestWrapper中重写的getInputStream()方法。大家可以看看API中关于HttpServletRequest的用法http://tomcat.apache.org/tomcat-5.5-doc/servletapi/index.html

posted @ 2016-11-22 16:00  跨境电商杂货铺  阅读(655)  评论(0编辑  收藏  举报