getReader() has already been called for this request

Bertha 。 2023-09-28 11:52 216阅读 0赞

问题现场:

2bdfb985918e49259c9746e86f5753ac.png

原因:

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,我们改成这样用:

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

效果:
af38c8b1a24b4304a0a1080ea7656d61.png

好的,这篇就到这。

发表评论

表情:
评论列表 (有 0 条评论,216人围观)

还没有评论,来说两句吧...

相关阅读