服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - Java教程 - 关于Filter中获取请求体body后再次读取的问题

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

2022-09-23 12:12fayeyiwang Java教程

这篇文章主要介绍了关于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

延伸 · 阅读

精彩推荐
  • Java教程Java线程并发中常见的锁机制详细介绍

    Java线程并发中常见的锁机制详细介绍

    越来越多的互联网企业面临着用户量膨胀而带来的并发安全问题。接下来通过本文给大家介绍Java线程并发中常见的锁机制,感兴趣的朋友一起看看吧 ...

    路上有多远3702020-05-05
  • Java教程springboot 在idea中实现热部署的方法

    springboot 在idea中实现热部署的方法

    这篇文章主要介绍了springboot 在idea中实现热部署的方法,实现了热部署,在每一次作了修改之后,都会自动的重启,非常节约时间,感兴趣的小伙伴们可以...

    maybe_u_like_鱼香茄子10582021-06-06
  • Java教程浅谈IDEA中Maven配置问题全解决

    浅谈IDEA中Maven配置问题全解决

    这篇文章主要介绍了浅谈IDEA中Maven配置问题全解决,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下...

    CringKong5882020-07-25
  • Java教程Java进阶教程之IO基础

    Java进阶教程之IO基础

    这篇文章主要介绍了Java进阶教程之IO基础,这里只是对Java IO的基本介绍,包含读取和写入等操作,需要的朋友可以参考下 ...

    Vamei5672019-11-27
  • Java教程浅谈Java模板引擎性能对比

    浅谈Java模板引擎性能对比

    本篇文章主要介绍了浅谈Java模板引擎性能对比 ,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧...

    Kayen15692021-01-08
  • Java教程java 二维码的生成与解析示例代码

    java 二维码的生成与解析示例代码

    本文主要介绍java二维码的生成与解析,这里提供示例代码以便大家参考和理解,希望能帮助开发Java 二维码的朋友 ...

    人生设计师2792020-06-02
  • Java教程Java实现动态代理的实例代码

    Java实现动态代理的实例代码

    代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处...

    随身电源10782022-01-21
  • Java教程idea中@Autowired注解下变量报红的解决

    idea中@Autowired注解下变量报红的解决

    这篇文章主要介绍了idea中@Autowired注解下变量报红的解决,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...

    dxj10168052022-07-11