国产化驱动经济自主性与科技创新的未来之路
1370
2022-10-21
关于Filter中获取请求体body后再次读取的问题
Filter获取请求体body再次读取
工作需要,要将请求和响应做一些处理,写一个filter拦截请求,拦截request中body内容后,字符流关闭,controller取到的请求体内容为空。
从Request中获取输入流,InputStream只能被读取一次。
解决方案
给request添加一个包装类BodyWrapper,继承HttpServletRequestWrapper,
先从request中取输入流,读取流中的数据,然后重写getInputStream()和getReader()方法。
chain.doFilter(requestWrapper, response);
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;ixOmYzLo
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
return super.getHeaderNames();
}
@Override
public Enumeration
return super.getHeaders(name);
}
}
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中写法如下:
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
Map
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了
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
/**
* 前缀排除 如 /static/goods 排除
*/
List
/**
* 排除过滤路径
*/
List
@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;
}
}
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) {
}
};
}
}
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~