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

网友投稿 1370 2022-10-21

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

关于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 getHeaderNames() {undefined

return super.getHeaderNames();

}

@Override

public Enumeration getHeaders(String name) {undefined

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 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了

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 ignore = Arrays.asList("/xxxx");

/**

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

*/

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

/**

* 排除过滤路径

*/

List 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;

}

}

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小时内删除侵权内容。

上一篇:APM - Golang应用程序的一个进程管理器拥有一个HTTP API
下一篇:Python Flask定时调度疫情大数据爬取全栈项目实战-1.项目环境准备及Jupyter Notebook安装和启动
相关文章

 发表评论

暂时没有评论,来抢沙发吧~