如何解决getReader() has already been called for this request问题

 更新时间:2024年05月11日 09:55:35   作者:终遇你..  
这篇文章主要介绍了如何解决getReader() has already been called for this request问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教

解决getReader() has already been called for this request

在 Filter 中对 request 中的 body 进行参数签名校验

会报如下错误:

getReader() has already been called for this request

原因是

request.getReader() 和 request.getInputStream() 都是只能调用一次

并且 getReader() 方法底层也是调用 getInputStream() 来实现的.

所以我们要使用 HttpServletRequestWrapper 来实现自定义的 CustomHttpServletRequestWrapper, 把 body 保存在 CustomHttpServletRequestWrapper 中, 并且重写 getInputStream() 方法

重写  HttpServletRequestWrapper

package com.fosung.pb.village.config;
 
import org.apache.commons.fileupload.servlet.ServletFileUpload;
 
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
 
public class MyRequestWrapper extends HttpServletRequestWrapper {
 
    private byte[] body;
    public MyRequestWrapper(HttpServletRequest request) throws IOException {
        super(request);
        if(ServletFileUpload.isMultipartContent(request)){
            return;
        }
        StringBuilder sb = new StringBuilder();
        String line;
        BufferedReader reader = request.getReader();
        while ((line = reader.readLine()) != null) {
            sb.append(line);
        }
        String body = sb.toString();
        this.body = body.getBytes(StandardCharsets.UTF_8);
    }
    public String getBody() {
        return new String(this.body , StandardCharsets.UTF_8) ;
    }
    @Override
    public ServletInputStream getInputStream() {
        final ByteArrayInputStream bais = new ByteArrayInputStream(body);
        return new ServletInputStream() {
            @Override
            public boolean isFinished() {
                return false;
            }
            @Override
            public boolean isReady() {
                return false;
            }
            @Override
            public void setReadListener(ReadListener readListener) {
            }
            @Override
            public int read(){
                return bais.read();
            }
        };
    }
    @Override
    public BufferedReader getReader(){
        return new BufferedReader(new InputStreamReader(this.getInputStream()));
    }
}

Filter 使用

package com.fosung.pb.village.config;
 
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
 
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
 
/**
 * @author lanx
 * @date 2022/4/11
 */
@Slf4j
@Component
@WebFilter(filterName = "AntiSqlInjectionfilter", urlPatterns = "/*")
public class AntiSqlInjectionfilter implements Filter {
 
    public void destroy() {
        // TODO Auto-generated method stub
    }
 
    public void init(FilterConfig arg0) throws ServletException {
        // TODO Auto-generated method stub
    }
 
 
    public void doFilter(ServletRequest request, ServletResponse response,
                         FilterChain chain) throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) request;
        HttpServletResponse res = (HttpServletResponse) response;
        MyRequestWrapper myRequestWrapper = null;
        // 获取请求body
        try {
            myRequestWrapper = new MyRequestWrapper(req);
        } catch (IOException e) {
            log.error("get request body exception", e);
            throw new RuntimeException(e);
        }
 
        if ("POST".equalsIgnoreCase(req.getMethod())) {
            String param = myRequestWrapper.getBody();
            chain.doFilter(myRequestWrapper, response);
        } else {
            chain.doFilter(myRequestWrapper, response);
        }
    }
    
}

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • Java Spring数据单元配置过程解析

    Java Spring数据单元配置过程解析

    这篇文章主要介绍了Java Spring数据单元配置过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-12-12
  • Java请求转发和请求重定向区别详解

    Java请求转发和请求重定向区别详解

    这篇文章主要介绍了Java请求转发和请求重定向区别详解,请求转发和请求重定向,但二者是完全不同的,所以我们今天就来盘他们的区别介绍,需要的朋友可以参考一下
    2022-07-07
  • SpringBoot集成RocketMQ发送事务消息的原理解析

    SpringBoot集成RocketMQ发送事务消息的原理解析

    RocketMQ 的事务消息提供类似 X/Open XA 的分布事务功能,通过事务消息能达到分布式事务的最终一致,这篇文章主要介绍了SpringBoot集成RocketMQ发送事务消息,需要的朋友可以参考下
    2022-06-06
  • 华为技术专家讲解JVM内存模型(收藏)

    华为技术专家讲解JVM内存模型(收藏)

    这篇文章主要介绍了华为技术专家讲解JVM内存模型(收藏)的相关知识,本文给大家介绍的非常详细,具有一定的收藏借鉴价值,需要的朋友可以参考下
    2021-05-05
  • Java 异步线程监听与结果回调及异常捕获总结分析

    Java 异步线程监听与结果回调及异常捕获总结分析

    异常是程序之中导致程序中断的一种指令流,异常一旦出现并且没有进行合理处理的话,那么程序就将中断执行,这篇文章综合介绍了异步线程监听与结果回调及异常捕获
    2021-11-11
  • MyBatis解决模糊查询包含特殊字符问题

    MyBatis解决模糊查询包含特殊字符问题

    这篇文章主要介绍了MyBatis解决模糊查询包含特殊字符问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-02-02
  • Java中避免空指针异常的方法

    Java中避免空指针异常的方法

    这篇文章主要介绍了Java中避免空指针异常的方法,本文讨论Optional类型、Objects类等技术,需要的朋友可以参考下
    2014-10-10
  • JAVA如何解决并发问题

    JAVA如何解决并发问题

    这篇文章主要介绍了JAVA如何解决并发问题的处理方法,文中讲解的非常细致,代码帮助大家更好的理解和学习,感兴趣的朋友可以了解下
    2020-06-06
  • Zookeeper事务日志预分配空间解读

    Zookeeper事务日志预分配空间解读

    这篇文章主要介绍了Zookeeper事务日志预分配空间解读,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-04-04
  • 详解Spring Cloud负载均衡重要组件Ribbon中重要类的用法

    详解Spring Cloud负载均衡重要组件Ribbon中重要类的用法

    本篇文章主要介绍了详解Spring Cloud负载均衡重要组件Ribbon中重要类的用法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-03-03

最新评论