好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

关于Filter中获取请求体body后再次读取的问题

Filter获取请求体body再次读取

工作需要,要将请求和响应做一些处理,写一个filter拦截请求,拦截request中body内容后,字符流关闭,controller取到的请求体内容为空。

从Request中获取输入流,InputStream只能被读取一次。

解决方案

给request添加一个包装类BodyWrapper,继承HttpServletRequestWrapper,

先从request中取输入流,读取流中的数据,然后重写getInputStream()和getReader()方法。

?

1

chain.doFilter(requestWrapper, response);

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

import java.io.BufferedReader;

import java.io.ByteArrayInputStream;

import java.io.IOException;

import java.io.InputStreamReader;

import java.nio.charset.Charset;

import java.util.Enumeration;

import javax.servlet.ReadListener;

import javax.servlet.ServletInputStream;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletRequestWrapper;

import com.xera.fsafesso.HttpHelper;

public class BodyWrapper extends HttpServletRequestWrapper {undefined

    private final byte [] body;

    public BodyWrapper(HttpServletRequest request) throws IOException {undefined

        super (request);

        body = HttpHelper.getBodyString(request).getBytes(Charset.forName( "UTF-8" ));

    }

    @Override

    public BufferedReader getReader() throws IOException {undefined

        return new BufferedReader( new InputStreamReader(getInputStream()));

    }

    @Override

    public ServletInputStream getInputStream() throws IOException {undefined

        final ByteArrayInputStream bais = new ByteArrayInputStream(body);

        return new ServletInputStream(){undefined

            @Override

            public int read() throws IOException {undefined

                return bais.read();

            }

            @Override

            public boolean isFinished() {undefined

                return false ;

            }

            @Override

            public boolean isReady() {undefined

                return false ;

            }

            @Override

            public void setReadListener(ReadListener arg0) {undefined

            }

        };

    }

    @Override

    public String getHeader(String name) {undefined

        return super .getHeader(name);

    }

    @Override

    public Enumeration<String> getHeaderNames() {undefined

        return super .getHeaderNames();

    }

    @Override

    public Enumeration<String> getHeaders(String name) {undefined

        return super .getHeaders(name);

    }

}

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

import java.io.BufferedReader;

import java.io.IOException;

import java.io.InputStream;

import java.io.InputStreamReader;

import java.nio.charset.Charset;

import javax.servlet.ServletRequest;

public class HttpHelper {undefined

      /**

      * 获取请求Body

      * @param request

      * @return

      */

    public static String getBodyString(ServletRequest request) {undefined

        StringBuilder sb = new StringBuilder();

        InputStream inputStream = null ;

        BufferedReader reader = null ;

        try {undefined

            inputStream = request.getInputStream();

            reader = new BufferedReader( new InputStreamReader(inputStream, Charset.forName( "UTF-8" )));

            String line = "" ;

            while ((line = reader.readLine()) != null ) {undefined

                sb.append(line);

            }

        } catch (IOException e) {undefined

            e.printStackTrace();

        } finally {undefined

            if (inputStream != null ) {undefined

                try {undefined

                    inputStream.close();

                } catch (IOException e) {undefined

                    e.printStackTrace();

                }

            }

            if (reader != null ) {undefined

                try {undefined

                    reader.close();

                } catch (IOException e) {undefined

                    e.printStackTrace();

                }

            }

        }

        return sb.toString();

    }

}

Filter中写法如下:

?

1

2

3

4

5

6

HttpServletRequest httpServletRequest = (HttpServletRequest) request;

            Map<String, String> requestMap = this .getTypesafeRequestMap(httpServletRequest);

            requestWrapper = new BodyWrapper(httpServletRequest);

            String body = HttpHelper.getBodyString(requestWrapper);

            log.info( "loggingFilter---请求路径 {},请求参数 {},请求体内容 {}" ,httpServletRequest.getRequestURL(),requestMap,body);

      chain.doFilter(requestWrapper, response);

在使用注解的方式(即@WebFilter)声明过滤器时,

需要再main函数类上添加@ServletComponentScan(basePackages = "此处写明类地址,格式为包名+类名(如com.*) 

Http请求解决body流一旦被读取了就无法二次读取情况

相信大家在工作当中,经常会遇到需要处理http请求及响应body的场景,这里最大的问题应该就是body中流以但被读取就无法二次读取了。

解决request请求流只能读取一次的问题

我们编写一个过滤器,这样就可以重写body了

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

package com.interceptor;

import java.io.IOException;

import java.util.Arrays;

import java.util.List;

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.HttpServletResponse;

 

public class MyFilter implements Filter {

     private static String privateKey ;   

     public String getPrivateKey() {

         return privateKey;

     }

     public void setPrivateKey(String key) {

         privateKey = key;

     }

 

     /**

      *  排除过滤路径

      */

     List<String> ignore = Arrays.asList( "/xxxx" );

    

     /**

      *   前缀排除   如 /static/goods 排除

      */

     List<String> ignorePrefix = Arrays.asList( "/css/" , "/pop/" , "/js/" , "/static/" , "/images/" , "/favicon.ico" );

    

     /**

      *  排除过滤路径

      */

     List<String> ignoreSuffix = Arrays.asList( "/test" );

    

     @Override

     public void init(FilterConfig filterConfig) throws ServletException {

         //过滤器初始化

     }

     @Override

     public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

         // 防止流读取一次后就没有了, 所以需要将流继续写出去

         HttpServletRequest request = (HttpServletRequest) servletRequest;

         HttpServletResponse response = (HttpServletResponse) servletResponse;

         String uri = request.getServletPath();

         response.setContentType( "application/json;charset=UTF-8" );

         ServletRequest requestWrapper = null ;

         if (canIgnore(uri)) {

             requestWrapper = new MyFilterBodyReaderHttpServletRequestWrapper(request);

             filterChain.doFilter(requestWrapper, response);

             return ;

         }

         try {

             requestWrapper = new MyFilterBodyReaderHttpServletRequestWrapper(request, response, privateKey);

         } catch (Exception e) {

             e.printStackTrace();

             return ;

         }

         filterChain.doFilter(requestWrapper, servletResponse);

     }

 

     @Override

     public void destroy() {

         //过滤器销毁

     }

    

     private boolean canIgnore(String uri) { 

        

         logger.info( "过滤器  request  uri : {} " ,uri);

         boolean isExcludedPage = false ;

         for (String page : ignore) {

             if (uri.equals(page)) {

                 logger.info( "请求路径不需要拦截,忽略该uri : {} " ,uri);

                 isExcludedPage = true ;

                 break ;

             }

         }

        

         for (String prefix : ignorePrefix) {

             if (uri.startsWith(prefix)) {

                 logger.info( "请求路径前缀[{}],不拦截该uri : {} " , prefix, uri);

                 isExcludedPage = true ;

                 break ;

             }

         }

        

         for (String prefix : ignoreSuffix) {

             if (uri.endsWith(prefix)) {

                 logger.info( "请求路径后缀[{}],不拦截该uri : {} " , prefix, uri);

                 isExcludedPage = true ;

                 break ;

             }

         }

         return isExcludedPage;

     }

}

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

package com.interceptor;

import java.io.BufferedReader;

import java.io.ByteArrayInputStream;

import java.io.ByteArrayOutputStream;

import java.io.IOException;

import java.io.InputStream;

import java.io.InputStreamReader;

import java.nio.charset.Charset;

import java.util.Map;

import javax.servlet.ReadListener;

import javax.servlet.ServletInputStream;

import javax.servlet.ServletRequest;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletRequestWrapper;

import javax.servlet.http.HttpServletResponse;

import com.alibaba.fastjson.JSON;

 

/**

* @Description: TODO 过滤器处理requestbody获取一次就失效

*/

public class MyFilterBodyReaderHttpServletRequestWrapper extends HttpServletRequestWrapper {

     private final byte [] body;

     /**

      * TODO 重写requestbody

      * @param request

      * @throws IOException

      */

     public MyFilterBodyReaderHttpServletRequestWrapper(HttpServletRequest request) throws IOException {

         super (request);

         String sessionStream = getBodyString(request);

         body = sessionStream.getBytes(Charset.forName( "UTF-8" ));

     }

 

     /**

      * TODO 拦截解密,校验,重写requestbody

      */

     @SuppressWarnings ({ "rawtypes" , "unchecked" })

     public MyFilterBodyReaderHttpServletRequestWrapper(HttpServletRequest request,HttpServletResponse response, String clientKey, Boolean ignoreCheckSign) throws Exception {

         super (request);

         String sessionStream = getBodyString(request);

         Map paramMap = (Map) JSON.parse(sessionStream);

       /**

         *自己项目中与合作方的加解密内容

         *如:String data= (String) paramMap.get("data");

         *    String json=xxxxxutil.decrypt(参数);

       */

         body = json.getBytes(Charset.forName( "UTF-8" ));

     }

    

     /**

     * TODO 获取请求Body

     * @param request

     * @return

     * @throws

     */

     public String getBodyString( final ServletRequest request) {

         StringBuilder sb = new StringBuilder();

         InputStream inputStream = null ;

         BufferedReader reader = null ;

         try {

             inputStream = cloneInputStream(request.getInputStream());

             reader = new BufferedReader( new InputStreamReader(inputStream, Charset.forName( "UTF-8" )));

             String line = "" ;

             while ((line = reader.readLine()) != null ) {

                 sb.append(line);

             }

         }

         catch (IOException e) {

             e.printStackTrace();

         }

         finally {

             if (inputStream != null ) {

                 try {

                     inputStream.close();

                 }

                 catch (IOException e) {

                     e.printStackTrace();

                 }

             }

             if (reader != null ) {

                 try {

                     reader.close();

                 }

                 catch (IOException e) {

                     e.printStackTrace();

                 }

             }

         }

         return sb.toString();

     }

    

     /**

     * TODO 无参获取请求Body

     * @return

     * @throws

     */

     public String getBodyString() {

         if (body == null ) {

             return null ;

         }

         String str = new String(body);

         return str;

     }

 

     /**

     * TODO 复制输入流

     * @param inputStream

     * @return

     * @throws

     */

     public InputStream cloneInputStream(ServletInputStream inputStream) {

         ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();

         byte [] buffer = new byte [ 1024 ];

         int len;

         try {

             while ((len = inputStream.read(buffer)) > - 1 ) {

                 byteArrayOutputStream.write(buffer, 0 , len);

             }

             byteArrayOutputStream.flush();

         }

         catch (IOException e) {

             e.printStackTrace();

         }

         InputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());

         return byteArrayInputStream;

     }

     @Override

     public BufferedReader getReader() throws IOException {

         return new BufferedReader( new InputStreamReader(getInputStream()));

     }

 

     @Override

     public ServletInputStream getInputStream() throws IOException {

         final ByteArrayInputStream bais = new ByteArrayInputStream(body);

         return new ServletInputStream() {

 

             @Override

             public int read() throws IOException {

                 return bais.read();

             }

 

             @Override

             public boolean isFinished() {

                 return false ;

             }

 

             @Override

             public boolean isReady() {

                 return false ;

             }

 

             @Override

             public void setReadListener(ReadListener readListener) {

             }

         };

     }

}

以上为个人经验,希望能给大家一个参考,也希望大家多多支持。

原文链接:https://blog.csdn.net/fayeyiwang/article/details/92836181

查看更多关于关于Filter中获取请求体body后再次读取的问题的详细内容...

  阅读:39次