• getReader() has already been called for this request


    问题现场:

    原因:

    HttpServletRequest 的 getInputStream() 和 getReader() 都只能读取一次。

    因为 我们使用@RequestBody 注解,读取body参数;而 又 写了拦截器,也需要将post请求,body数据拿出来。
    由于@RequestBody 也是流的形式读取,流读了一次就没有了。

    解决方案:

    过滤器是优先于拦截器的, 我们写一个过滤器,在过滤器里面 把流数据 copy一份出来用,也就是复写一哈。
    在拦截器上使用我们复写的流数据就行。

    BodyWrapperFilter.java

    1. import javax.servlet.*;
    2. import javax.servlet.http.HttpServletRequest;
    3. import java.io.IOException;
    4. /**
    5. * @Author: JCccc
    6. * @Date: 2022-6-12 10:35
    7. * @Description:
    8. */
    9. public class BodyWrapperFilter implements Filter {
    10. @Override
    11. public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
    12. ServletRequest requestWrapper = null;
    13. if(servletRequest instanceof HttpServletRequest) {
    14. requestWrapper = new CustomHttpServletRequestWrapper((HttpServletRequest) servletRequest);
    15. }
    16. if(requestWrapper == null) {
    17. filterChain.doFilter(servletRequest, servletResponse);
    18. } else {
    19. filterChain.doFilter(requestWrapper, servletResponse);
    20. }
    21. }
    22. }

    CustomHttpServletRequestWrapper.java

    1. import javax.servlet.ReadListener;
    2. import javax.servlet.ServletInputStream;
    3. import javax.servlet.http.HttpServletRequest;
    4. import javax.servlet.http.HttpServletRequestWrapper;
    5. import java.io.*;
    6. import java.nio.charset.StandardCharsets;
    7. /**
    8. * @Author: JCccc
    9. * @Date: 2022-6-12 10:36
    10. * @Description: 重写一个自己的 RequestWrapper 拿出body给自己用
    11. */
    12. public class CustomHttpServletRequestWrapper extends HttpServletRequestWrapper {
    13. private byte[] body;
    14. public CustomHttpServletRequestWrapper(HttpServletRequest request) throws IOException {
    15. super(request);
    16. BufferedReader reader = request.getReader();
    17. try (StringWriter writer = new StringWriter()) {
    18. int read;
    19. char[] buf = new char[1024 * 8];
    20. while ((read = reader.read(buf)) != -1) {
    21. writer.write(buf, 0, read);
    22. }
    23. this.body = writer.getBuffer().toString().getBytes();
    24. }
    25. }
    26. public String getBody(){
    27. return new String(body, StandardCharsets.UTF_8);
    28. }
    29. @Override
    30. public ServletInputStream getInputStream() {
    31. final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body);
    32. return new ServletInputStream() {
    33. @Override
    34. public boolean isFinished() {
    35. return false;
    36. }
    37. @Override
    38. public boolean isReady() {
    39. return false;
    40. }
    41. @Override
    42. public void setReadListener(ReadListener readListener) {
    43. }
    44. @Override
    45. public int read() {
    46. return byteArrayInputStream.read();
    47. }
    48. };
    49. }
    50. @Override
    51. public BufferedReader getReader() {
    52. return new BufferedReader(new InputStreamReader(this.getInputStream()));
    53. }
    54. }

    WebApplicationConfig.java

    1. import org.springframework.boot.web.servlet.FilterRegistrationBean;
    2. import org.springframework.context.annotation.Bean;
    3. import org.springframework.context.annotation.Configuration;
    4. /**
    5. * @Author: JCccc
    6. * @Date: 2022-6-23 10:52
    7. * @Description:
    8. */
    9. @Configuration
    10. public class WebApplicationConfig {
    11. @Bean
    12. BodyWrapperFilter getBodyWrapperFilter(){
    13. return new BodyWrapperFilter();
    14. }
    15. @Bean("bodyWrapperFilter")
    16. public FilterRegistrationBean<BodyWrapperFilter> checkUserFilter(BodyWrapperFilter bodyWrapperFilter) {
    17. FilterRegistrationBean<BodyWrapperFilter> registrationBean = new FilterRegistrationBean();
    18. registrationBean.setFilter(bodyWrapperFilter);
    19. registrationBean.addUrlPatterns("/*");
    20. registrationBean.setOrder(1);
    21. registrationBean.setAsyncSupported(true);
    22. return registrationBean;
    23. }
    24. }

    然后就是在拦截器里面,如果我们想取出body,我们改成这样用:
     

    CustomHttpServletRequestWrapper wrapper = (CustomHttpServletRequestWrapper) request;
    String  nowParams = wrapper.getBody();

    效果:

     

    好的,这篇就到这。 

  • 相关阅读:
    SpringMVC工作流程
    带你一张图了解八种流行的网络协议
    【Unity基础】5.动画曲线
    MR混合现实在临床医学课堂教学中的应用演示
    【论文精读7】MVSNet系列论文详解-PVA-MVSNet
    MoneyPrinterPlus:AI自动短视频生成工具-阿里云配置详解
    eclipse配置Tomcat和Tomcat出现无效端口解决办法
    Pytorch利用图像分割识别手势验证码(Deeplabv3)
    Tomcat总体架构,启动流程与处理请求流程
    8.查询数据
  • 原文地址:https://blog.csdn.net/qq_35387940/article/details/125423192