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