实现 多次读取

时间:2025-03-20 11:21:56

转载自:/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;
    }
}