代码之家  ›  专栏  ›  技术社区  ›  vigamage

使用HttpServletRequestWrapper制作副本后,缺少所需的请求正文

  •  5
  • vigamage  · 技术社区  · 7 年前

    在我的项目中,我有一组api调用,这些调用应该通过特定的公共验证集进行过滤。在这种情况下,我必须在请求到达REST控制器之前拦截请求,读取请求正文,进行验证,如果请求通过了验证,则将其传递给控制器。

    HttpServletRequest 不能反序列化多次,我使用了 HttpServletRequestWrapper

    以下是用于拦截请求的配置类。

    public class InterceptorConfig extends WebMvcConfigurerAdapter {
    
         @Autowired     
         CustomInterceptor customInterceptor;
    
         @Override  
         public void addInterceptors(InterceptorRegistry registry) { 
            registry.addInterceptor(customInterceptor).addPathPatterns("/signup/**");
    
         }   
    }
    

    这是我的 preHandle 方法内部 CustomInterceptor HandlerInterceptorAdaptor

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    
        ServletRequest copiedRequest = new HttpRequestWrapper(request);
    
        Map<String, Object> jsonMap = mapper.readValue(copiedRequest.getInputStream(), Map.class);
    
        if(jsonMap.containsKey("userId")){
            long userId = jsonMap.get("userId");
            MyClass myObject= myAutowiredService.getMyObject(userId);
            if(myObject == null){
                response.setStatus(HttpStatus.SC_NOT_ACCEPTABLE);
                return false;
            } 
            // some more validations which end up returning false if they are met
        }
        return true;
    }
    

    HttpRequestWrapper

    public class HttpRequestWrapper extends HttpServletRequestWrapper {
    
        private byte[] requestBody;
    
        public HttpRequestWrapper(HttpServletRequest request) throws IOException{
            super(request);
    
            try {
                requestBody = IOUtils.toByteArray(request.getInputStream());
            } catch (IOException ex) {
                requestBody = new byte[0];
            }
        }
    
        @Override
        public ServletInputStream getInputStream() throws IOException {
    
            final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(requestBody);
    
            return new ServletInputStream() {
    
                @Override
                public boolean isFinished() {
                    return byteArrayInputStream.available() == 0;
                }
    
                @Override
                public boolean isReady() {
                    return true;
                }
    
                @Override
                public void setReadListener(ReadListener listener) {
                    throw new RuntimeException("Not implemented");
                }
    
                public int read () throws IOException {
                    return byteArrayInputStream.read();
                }
            };
        }
    
    }
    

    /signup/**

    通用域名格式。我的包裹。我的回应对象 通用域名格式。我的包裹。我的控制器。myControllerMethod(com.mypackage.myDTO)

    1 回复  |  直到 7 年前
        1
  •  2
  •   shazin    7 年前

    问题似乎是您正在使用拦截器来读取 HttpServletRequest InputStream 把它包起来 HttpRequestWrapper

    我认为你应该使用 Filter

    public class CustomFilter extends OncePerRequestFilter {
        public void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
            ServletRequest copiedRequest = new HttpRequestWrapper(request);
    
            Map<String, Object> jsonMap = mapper.readValue(copiedRequest.getInputStream(), Map.class);
    
            if(jsonMap.containsKey("userId")){
                long userId = jsonMap.get("userId");
                MyClass myObject= myAutowiredService.getMyObject(userId);
                if(myObject == null){
                    response.setStatus(HttpStatus.SC_NOT_ACCEPTABLE);
                    //return false;
                } 
                // some more validations which end up returning false if they are met
             }
    
             filterChain.doFilter(copiedRequest, (ServletResponse) response);
        }
    }
    

    你需要在任何一种情况下使用这个过滤器 web.xml WebApplicationInitializer