解决getreader() has already been called for this request
在 filter 中对 request 中的 body 进行参数签名校验
会报如下错误:
getreader() has already been called for this request
原因是
request.getreader() 和 request.getinputstream() 都是只能调用一次
并且 getreader() 方法底层也是调用 getinputstream() 来实现的.
所以我们要使用 httpservletrequestwrapper 来实现自定义的 customhttpservletrequestwrapper, 把 body 保存在 customhttpservletrequestwrapper 中, 并且重写 getinputstream() 方法
重写 httpservletrequestwrapper
package com.fosung.pb.village.config; import org.apache.commons.fileupload.servlet.servletfileupload; import javax.servlet.readlistener; import javax.servlet.servletinputstream; import javax.servlet.http.httpservletrequest; import javax.servlet.http.httpservletrequestwrapper; import java.io.bufferedreader; import java.io.bytearrayinputstream; import java.io.ioexception; import java.io.inputstreamreader; import java.nio.charset.standardcharsets; public class myrequestwrapper extends httpservletrequestwrapper { private byte[] body; public myrequestwrapper(httpservletrequest request) throws ioexception { super(request); if(servletfileupload.ismultipartcontent(request)){ return; } stringbuilder sb = new stringbuilder(); string line; bufferedreader reader = request.getreader(); while ((line = reader.readline()) != null) { sb.append(line); } string body = sb.tostring(); this.body = body.getbytes(standardcharsets.utf_8); } public string getbody() { return new string(this.body , standardcharsets.utf_8) ; } @override public servletinputstream getinputstream() { final bytearrayinputstream bais = new bytearrayinputstream(body); return new servletinputstream() { @override public boolean isfinished() { return false; } @override public boolean isready() { return false; } @override public void setreadlistener(readlistener readlistener) { } @override public int read(){ return bais.read(); } }; } @override public bufferedreader getreader(){ return new bufferedreader(new inputstreamreader(this.getinputstream())); } }
filter 使用
package com.fosung.pb.village.config; import lombok.extern.slf4j.slf4j; import org.springframework.stereotype.component; import javax.servlet.*; import javax.servlet.annotation.webfilter; import javax.servlet.http.httpservletrequest; import javax.servlet.http.httpservletresponse; import java.io.ioexception; /** * @author lanx * @date 2022/4/11 */ @slf4j @component @webfilter(filtername = "antisqlinjectionfilter", urlpatterns = "/*") public class antisqlinjectionfilter implements filter { public void destroy() { // todo auto-generated method stub } public void init(filterconfig arg0) throws servletexception { // todo auto-generated method stub } public void dofilter(servletrequest request, servletresponse response, filterchain chain) throws ioexception, servletexception { httpservletrequest req = (httpservletrequest) request; httpservletresponse res = (httpservletresponse) response; myrequestwrapper myrequestwrapper = null; // 获取请求body try { myrequestwrapper = new myrequestwrapper(req); } catch (ioexception e) { log.error("get request body exception", e); throw new runtimeexception(e); } if ("post".equalsignorecase(req.getmethod())) { string param = myrequestwrapper.getbody(); chain.dofilter(myrequestwrapper, response); } else { chain.dofilter(myrequestwrapper, response); } } }
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。
发表评论