Springboot如何设置过滤器及重复读取request⾥的body
⽬录
HttpServletRequest的输⼊流只能读取⼀次的原因
重复读取body中数据的⽅法
springboot的过滤器
上⾯的getBody的代码
需求:
request的content-type为applciation/json,进⼊controller之前需要把body中的参数取出来做⼀次处理,然后和hearder中的另⼀个参数做对⽐。
思路:
加⼀个过滤器,在过滤器中取出参数做处理,然后⽐较
注意:
body⾥的数据⽤流来读取,只能读取⼀次
HttpServletRequest的输⼊流只能读取⼀次的原因
我们先来看看为什么HttpServletRequest的输⼊流只能读⼀次,当我们调⽤getInputStream()⽅法获取输⼊流时得到的是⼀个InputStream对象,⽽实际类型是ServletInputStream,它继承于InputStream。
InputStream的read()⽅法内部有⼀个postion,标志当前流被读取到的位置,每读取⼀次,该标志就会移动⼀次,如果读到最后,read()会返回-1,表⽰已经读取完了。如果想要重新读取则需要调⽤reset()⽅法,position就会移动到上次调⽤mark的位置,mark默认是0,所以就能从头再读了。调⽤reset()⽅法的前提是已经重写了reset()⽅法,当然能否reset也是有条件的,它取决于markSupported()⽅法是否返回true。InputStream默认不实现reset(),并且markSupported()默认也是返回false,这⼀点查看其源码便知:
我们再来看看ServletInputStream,可以看到该类没有重写mark(),reset()以及markSupported()⽅法:
综上,InputStream默认不实现reset的相关⽅法,⽽ServletInputStream也没有重写reset的相关⽅法,这样就⽆法重复读取流,这就是我们从request对象中获取的输⼊流就只能读取⼀次的原因。
重复读取body中数据的⽅法
这个⾃定义的requestWrapper继承了HttpServletRequestWrapper ,HttpServletRequestWrapper 是⼀个ServletRequest的包装类同时也是ServletRequest的实现类。
在这个⾃定义的requestWrapper⾥,⽤⼀个String做缓存,在构造⽅法⾥先把request的body中的数据缓存起来,然后重写了getInputStream,返回这个缓存的body,⽽不是从流中读取。
这样,在需要多次读取body的地⽅,只需要在过滤器中把原来的request换成这个⾃定义的request,然后把这个⾃定义的带缓存功能的request传到后续的过滤器链中。
public class BodyReaderRequestWrapper extends HttpServletRequestWrapper {
private final String body;
/**
*
* @param request
*/
public BodyReaderRequestWrapper(HttpServletRequest request) throws IOException{
super(request);
StringBuilder sb = new StringBuilder();
InputStream ins = InputStream();
BufferedReader isr = null;
try{
if(ins != null){
isr = new BufferedReader(new InputStreamReader(ins));
char[] charBuffer = new char[128];
int readCount = 0;
while((readCount = ad(charBuffer)) != -1){
sb.append(charBuffer,0,readCount);
}
}else{
sb.append("");
}
}catch (IOException e){
throw e;
}finally {
if(isr != null) {
isr.close();
}
}
body = sb.toString();
}
@Override
public BufferedReader getReader() throws IOException {
return new BufferedReader(new InputStream()));
}
@Override
public ServletInputStream getInputStream() throws IOException {
final ByteArrayInputStream byteArrayIns = new Bytes());
ServletInputStream servletIns = new ServletInputStream() {
@Override
public boolean isFinished() {
return false;
}
@Override
public boolean isReady() {
return false;
}
@Override
public void setReadListener(ReadListener readListener) {
}
@Override
public int read() throws IOException {
ad();
}
};
return  servletIns;
}
}
springboot的过滤器
2个注解:
@WebFilter(过滤器上)
@ServletComponentScan(加在启动类上,⽀持servlet components扫描(为了webfilter))
@Order(999) // 序号越低,优先级越⾼
// 加上WebFilter即可成为过滤器
@WebFilter(filterName="myFilter", urlPatterns="/api/workorder/service/selfAppeal")
public class ExternalFilter implements Filter  {
private final static Logger logger = Logger(ExternalFilter.class);
@Override
public void init(FilterConfig filterConfig) throws ServletException {
logger.info("filter init");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
throws IOException, ServletException {
ResponseObject object = new ResponseObject();
HttpServletRequest req = (HttpServletRequest)servletRequest;
HttpServletResponse res = (HttpServletResponse)servletResponse;
// ⼀个request的包装类,初始化时缓存了body,重写了getInputStream返回缓存的body,实现重复读取body
BodyReaderRequestWrapper requestWrapper  = new BodyReaderRequestWrapper(req);
String requestURI = RequestURI();
System.out.println("--------------------->过滤器:请求地址" + requestURI);
String md5 = Header("md5")  ;
if (md5 == null || !LowerCase().equals(MD5.Body(requestWrapper)).toLowerCase())) {            object.setStatus(501);
object.setStatusText("数据md5校验失败");
render(object, res);
return;
}
// 这⾥传递下去的就是⾃定义的request了,所以后续的Controller才能重复读取到body⾥的参数
filterChain.doFilter(requestWrapper, res);
}
@Override
public void destroy() {
}
spring怎么读怎么读/**
* @Title: render
* @Description: 发送Response
* @param object
* @param response void
* @author MasterYi
* @date 2020年1⽉15⽇上午10:48:45
*/
private void render(ResponseObject object, HttpServletResponse response) {
response.setContentType("application/json;charset=UTF-8");
try {
response.setStatus(200);
} catch (IOException e) {
<("ExternalFilter写⼊response异常");
}
}
}
上⾯的getBody的代码
从body中取值的具体操作
public class ReqGetBody {
static public String getBody(HttpServletRequest request) {
try {
ServletInputStream in = InputStream();
String body;
body = pyToString(in, Charset.forName("UTF-8"));
return body;
} catch (IOException e) {
e.printStackTrace();
return "";
}
}
}
以上为个⼈经验,希望能给⼤家⼀个参考,也希望⼤家多多⽀持。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。