• 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

  • 相关阅读:
    算法
    UVA 10318 Security Panel(DFS剪枝 + 状压 + 思维)题解
    CodeForces 509C Sums of Digits(贪心乱搞)题解
    UVA 10382 Watering Grass(区间覆盖,贪心)题解
    CodeForces 430A Points and Segments (easy)(构造)题解
    CodeForces 459C Pashmak and Buses(构造)题解
    newcoder F石头剪刀布(DFS + 思维)题解
    newcoder H肥猪(单调队列 / 线段树)题解
    UVALive 7501 Business Cycle(二分)题解
    UVALive 7503 Change(乱搞)题解
  • 原文地址:https://www.cnblogs.com/panxuejun/p/6089690.html
Copyright © 2020-2023  润新知