• HttpServletRequest重复读取


    原文链接:https://blog.csdn.net/weixin_43935907/article/details/93888343

    背景概述

    最近公司要求在之前的项目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 com.infosec.netsafess.controller.UserController.save(com.infosec.netsafess.entity.User)",
      "trace": "org.springframework.http.converter.HttpMessageNotReadableException: Required request body is missing: public void com.infosec.netsafess.controller.UserController.save(com.infosec.netsafess.entity.User)
    	at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.readWithMessageConverters(RequestResponseBodyMethodProcessor.java:160)
    	at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.resolveArgument(RequestResponseBodyMethodProcessor.java:130)
    	at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:126)
    	at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:167)
    	at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:134)
    	at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:104)
    	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:892)
    	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797)
    	at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
    	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1039)
    	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:942)
    	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1005)
    	at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:908)
    	at javax.servlet.http.HttpServlet.service(HttpServlet.java:660)
    	at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:882)
    	at javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
    	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
    	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    	at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
    	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    	at com.infosec.netsafess.filter.SignValidateFilter.doFilter(SignValidateFilter.java:28)
    	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    	at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99)
    	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    	at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:92)
    	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    	at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:93)
    	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    	at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200)
    	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:200)
    	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
    	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:490)
    	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)
    	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
    	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
    	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
    	at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:408)
    	at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
    	at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:836)
    	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1747)
    	at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
    	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    	at java.lang.Thread.run(Thread.java:748)
    ",
      "path": "/user/save"
    }

    大概的意思是说request里面的流只能使用一次,在拦截器中使用完了就不能再次使用,网上的攻略很多,有的说需要自己重写HttpServletRequestWrapper,有的说通过spring自带的ContentCachingRequestWrapper就可以,我复制过来了,然而并没有什么用,还是报那个错。但是我看网上有几个都说这样可以,后来才发现他们是在 chain.doFilter(requestWrapper, response)之后再通过requestWrapper.getContentAsByteArray方法获取数据,或者在filter中读取了inputstream之后,在controller接口方法中使用requestWrapper.getContentAsByteArray方法再获取数据,这样就不能使用@RequestBody自动注入参数了,这显然不是我想要达到的效果。

    我在他们的基础上做了一些修改,主要做的是读取了inputStream之后,再将数据写回去,具体实现如下:

    第一步重写HttpServletRequestWrapper

    package com.infosec.netsafess.filter;
    
    import java.io.BufferedReader;
    import java.io.ByteArrayInputStream;
    import java.io.IOException;
    import java.io.InputStreamReader;
    
    import javax.servlet.ReadListener;
    import javax.servlet.ServletInputStream;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletRequestWrapper;
    
    import org.apache.commons.io.IOUtils;
    
    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 = IOUtils.toByteArray(request.getInputStream());
            inputStream = new RequestCachingInputStream(body);
        }
    
        public byte[] getBody() {
            return body;
        }
    
        @Override
        public ServletInputStream getInputStream() throws IOException {
            if (inputStream != null) {
                return inputStream;
            }
            return super.getInputStream();
        }
    
        @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 inputStream.read();
            }
    
            @Override
            public boolean isFinished() {
                return inputStream.available() == 0;
            }
    
            @Override
            public boolean isReady() {
                return true;
            }
    
            @Override
            public void setReadListener(ReadListener readlistener) {
            }
    
        }
    
    }

    配置过滤器

    package com.infosec.netsafess.filter;
    
    import lombok.extern.java.Log;
    import org.apache.commons.io.IOUtils;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.stereotype.Component;
    
    import javax.servlet.*;
    import javax.servlet.annotation.WebFilter;
    import javax.servlet.http.HttpServletRequest;
    import java.io.IOException;
    
    @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 = IOUtils.toString(requestWrapper.getBody(),request.getCharacterEncoding());
            log.info(body);
            chain.doFilter(requestWrapper, response);
        }
    
        @Override
        public void destroy() {
    
        }
    }
    

    在拦截器中使用

    package com.infosec.netsafess.interceptor;
    
    import com.alibaba.fastjson.JSON;
    import com.alibaba.fastjson.JSONObject;
    import com.infosec.netsafess.annotation.LoginRequired;
    import com.infosec.netsafess.filter.ContentCachingRequestWrapper;
    import org.apache.commons.io.IOUtils;
    import org.springframework.web.method.HandlerMethod;
    import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.lang.reflect.Method;
    
    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 = handlerMethod.getMethod();
            //判断接口是否需要登录
            LoginRequired methodAnnotation = method.getAnnotation(LoginRequired.class);
            //有@LoginRequired注解,需要认证
            if(methodAnnotation != null){
                System.out.println("========================");
                ContentCachingRequestWrapper requestWapper = null;
                if(request instanceof HttpServletRequest){
                    requestWapper = (ContentCachingRequestWrapper) request;
                }
                String body = IOUtils.toString(requestWapper.getBody(),request.getCharacterEncoding());
                System.out.println(body);
                JSONObject obj = JSON.parseObject(body);
                System.out.println(obj);
            }
            return true;
        }
    }

    补充一点:拦截器是在过滤器的doFilter方法中执行的,根据debugger

  • 相关阅读:
    hadoop本地测试命令
    hadoop中文官网
    solr 5.2.1 tomcat 7 配置过程笔记
    很好的hadoop学习博客实际操作训练(旧版本)
    Tomcat7安装配置 for Ubuntu
    Solr with Apache Tomcat
    Linux 权限修改
    Ubuntu Server 下配置静态网络的方法
    Ubuntu Server 下的网络配置
    HBase 1.3(NOSQL) 发布,性能大幅提升
  • 原文地址:https://www.cnblogs.com/fswhq/p/13692165.html
Copyright © 2020-2023  润新知