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后再次读取的问题的详细内容...