当前位置: 首页 > 知识库问答 >
问题:

使用HttpServletquiestWrapper复制后,所需的请求主体丢失

鲍飞星
2023-03-14

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

由于HttpServletRequest不能多次反序列化,因此我使用HttpServletRequestWrapper来复制实际请求。使用它制作的副本,我进行验证。

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

public class InterceptorConfig extends WebMvcConfigurerAdapter {

     @Autowired     
     CustomInterceptor customInterceptor;

     @Override  
     public void addInterceptors(InterceptorRegistry registry) { 
        registry.addInterceptor(customInterceptor).addPathPatterns("/signup/**");

     }   
}

这是我在CustomInterceptor类中的preHandle方法,它扩展了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/**的模式向任何url发送请求时,所有验证都正常进行。然而,一旦请求命中控制器方法,就会弹出错误,表明请求主体不可用。

缺少所需的请求体:公共com.mypackage.my响应对象com.mypackage.myController.my控制器方法(com.mypackage.myDTO)

我正在努力寻找原因,以及克服这个问题的方法。我在课堂上做错了什么吗?还是有什么遗漏?

帮我解决这件事。

谢谢

共有1个答案

徐涵亮
2023-03-14

问题似乎是您正在使用Interceptor读取HttpServletRequestInputStream并将其包装在HttpResestWrapper中,但包装器永远不会返回。

我认为你应该使用过滤器

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.xmlWebApplication ation初始工具

 类似资料:
  • 我试图在flask应用程序上记录post请求,如下所示: 我这样做是因为我怀疑有时我会在POST上得到一个格式错误的JSON对象。我看到的问题是日志包含一个截断的请求体——它似乎被夹在中间... 我不能放日志摘要,因为它是敏感数据。。为什么请求被截断?我做错了吗? 谢谢

  • 我打下面的url使用任何Rest客户端,我得到api响应:400坏请求与响应体 输入参数 但是java simple client没有显示响应主体。。下面是java代码。。它只给出了400个坏请求。

  • 问题内容: 将请求正文与GET请求一起传递是否违反REST风格? 例如在Elasticsearch中过滤一些信息 甚至设计了一些工具来避免GET请求中的请求主体(例如邮递员) 问题答案: 从RFC: GET请求消息中的有效负载没有定义的语义。在GET请求上发送有效内容正文可能会导致某些现有实现拒绝该请求。 换句话说,这不是禁止的,但是它是未定义的行为,应避免使用。HTTP客户端,服务器和代理可以随

  • 问题内容: 所以我在与node.js一起运行的server.js文件中有以下代码。我正在使用express处理HTTP请求。 我在终端中运行以下命令: 运行该server.js后,将输出以下内容。 所以req.body是。我阅读了其他有关类似问题的Stack Overflow帖子,其中由于正文解析器,内容类型不正确。但这不是问题,因为内容类型是application / json。 有什么想法如何

  • 我有以下问题:我试图在Spring控制器处理POST请求之前获取它的主体。为此,我使用HandlerInterceptorAdapter的preHandle()方法。 如本讨论中所述 SpringREST服务:从请求中检索JSON 我也使用使用此包装器,我设法打印了第一个POST请求的正文,但第二个POST抛出一个IOException:流关闭。 您对如何获取所有POST请求的正文有什么想法吗?

  • 我正在用Application/JSON数据发送原始POST请求到邮递员服务器。我需要使用这个JSON对象,并在请求前脚本中追加一些数据。但是我只能找到如何访问环境变量,而不能请求主体。有人知道吗?谢了!