转载自:/2019/06/28/%E5%AE%9E%E7%8E%B0HttpServletRequest-getInputStream%E5%A4%9A%E6%AC%A1%E8%AF%BB%E5%8F%96/#%E8%83%8C%E6%99%AF%E6%A6%82%E8%BF%B0
叙述
最近公司要求在之前的项目APP接口里面加入端口校验功能,实现起来很简单,就是通过添加拦截器的方式,在interceptor中读取端口参数,校验该端口在配置文件中是否有存在,存在返回已占用,请重新输入,不存在就添加该服务。
接口中主要是json格式,其对应的是payload请求,不可以通过request的getParameter()方法直接获取,需要通过getRead或者getInputStream方法获取流,通过流读取body,将body转化成JsonObject来获取。读取之后就出现了下面的错误。
{
"timestamp": "2019-06-27T04:02:37.865+0000",
"status": 400,
"error": "Bad Request",
"message": "Required request body is missing: public void ()",
"trace": ": Required request body is missing: public void ()\r\n\tat (:160)\r\n\tat (:130)\r\n\tat (:126)\r\n\tat (:167)\r\n\tat (:134)\r\n\tat (:104)\r\n\tat (:892)\r\n\tat (:797)\r\n\tat (:87)\r\n\tat (:1039)\r\n\tat (:942)\r\n\tat (:1005)\r\n\tat (:908)\r\n\tat (:660)\r\n\tat (:882)\r\n\tat (:741)\r\n\tat (:231)\r\n\tat (:166)\r\n\tat (:53)\r\n\tat (:193)\r\n\tat (:166)\r\n\tat (:28)\r\n\tat (:193)\r\n\tat (:166)\r\n\tat (:99)\r\n\tat (:107)\r\n\tat (:193)\r\n\tat (:166)\r\n\tat (:92)\r\n\tat (:107)\r\n\tat (:193)\r\n\tat (:166)\r\n\tat (:93)\r\n\tat (:107)\r\n\tat (:193)\r\n\tat (:166)\r\n\tat (:200)\r\n\tat (:107)\r\n\tat (:193)\r\n\tat (:166)\r\n\tat (:200)\r\n\tat (:96)\r\n\tat (:490)\r\n\tat (:139)\r\n\tat (:92)\r\n\tat (:74)\r\n\tat (:343)\r\n\tat .http11.(:408)\r\n\tat (:66)\r\n\tat $(:836)\r\n\tat $(:1747)\r\n\tat (:49)\r\n\tat (:1149)\r\n\tat $(:624)\r\n\tat $(:61)\r\n\tat (:748)\r\n",
"path": "/user/save"
}
大概的意思是说request里面的流只能使用一次,在拦截器中使用完了就不能再次使用,网上的攻略很多,有的说需要自己重写HttpServletRequestWrapper,有的说通过spring自带的ContentCachingRequestWrapper就可以,我复制过来了,然而并没有什么用,还是报那个错。但是我看网上有几个都说这样可以,后来才发现他们是在 (requestWrapper, response)之后再通过方法获取数据,或者在filter中读取了inputstream之后,在controller接口方法中使用方法再获取数据,这样就不能使用@RequestBody自动注入参数了,这显然不是我想要达到的效果。
我在他们的基础上做了一些修改,主要做的是读取了inputStream之后,再将数据写回去,具体实现如下:
重写HttpServletRequestWrapper
package ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
public class ContentCachingRequestWrapper extends HttpServletRequestWrapper{
private byte[] body;
private BufferedReader reader;
private ServletInputStream inputStream;
public ContentCachingRequestWrapper(HttpServletRequest request) throws IOException{
super(request);
loadBody(request);
}
private void loadBody(HttpServletRequest request) throws IOException{
body = (());
inputStream = new RequestCachingInputStream(body);
}
public byte[] getBody() {
return body;
}
@Override
public ServletInputStream getInputStream() throws IOException {
if (inputStream != null) {
return inputStream;
}
return ();
}
@Override
public BufferedReader getReader() throws IOException {
if (reader == null) {
reader = new BufferedReader(new InputStreamReader(inputStream, getCharacterEncoding()));
}
return reader;
}
private static class RequestCachingInputStream extends ServletInputStream {
private final ByteArrayInputStream inputStream;
public RequestCachingInputStream(byte[] bytes) {
inputStream = new ByteArrayInputStream(bytes);
}
@Override
public int read() throws IOException {
return ();
}
@Override
public boolean isFinished() {
return () == 0;
}
@Override
public boolean isReady() {
return true;
}
@Override
public void setReadListener(ReadListener readlistener) {
}
}
}
配置过滤器
package ;
import ;
import ;
import org.;
import org.;
import ;
import .*;
import ;
import ;
import ;
@Component
@Log
@WebFilter(filterName = "test",urlPatterns = "/*")
public class SignValidateFilter implements Filter{
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
ContentCachingRequestWrapper requestWrapper = new ContentCachingRequestWrapper((HttpServletRequest) request);
String body = ((),());
(body);
(requestWrapper, response);
}
@Override
public void destroy() {
}
}
在拦截器中使用
package ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
public class AuthorityInterceptor extends HandlerInterceptorAdapter {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if(!(handler instanceof HandlerMethod)){
return true;
}
//START: 方法注解级拦截器
HandlerMethod handlerMethod = (HandlerMethod) handler;
Method method = ();
//判断接口是否需要登录
LoginRequired methodAnnotation = ();
//有@LoginRequired注解,需要认证
if(methodAnnotation != null){
("========================");
ContentCachingRequestWrapper requestWapper = null;
if(request instanceof HttpServletRequest){
requestWapper = (ContentCachingRequestWrapper) request;
}
String body = ((),());
(body);
JSONObject obj = (body);
(obj);
}
return true;
}
}