当前位置: 首页 > news >正文

住房和创新建设部网站网站的功能板块

住房和创新建设部网站,网站的功能板块,网站流程图设计,网站版权信息修改简介 HTTP 请求 RequestBody 只能被读取一次:HttpServletRequest 的输入流 (InputStream) 在被读取后会被关闭,导致后续无法再次读取。本文将介绍如何通过 请求包装类 (RequestWrapper) 来解决这个问题。问题背景 当我们需要在以下场景中多次读取 Reques…

简介

  • HTTP 请求 RequestBody 只能被读取一次HttpServletRequest 的输入流 (InputStream) 在被读取后会被关闭,导致后续无法再次读取。
  • 本文将介绍如何通过 请求包装类 (RequestWrapper) 来解决这个问题。

问题背景

当我们需要在以下场景中多次读取 RequestBody 时,就会遇到这个问题:

  1. 日志记录:需要在拦截器或过滤器中记录请求体
  2. 参数校验:需要在多个地方校验请求体数据
  3. 数据解析:需要在不同的组件中解析请求体(如 Spring 的 @RequestBody 和手动解析)

直接尝试多次读取 InputStream 会导致异常:

// 第一次读取(可以成功)
String body1 = IOUtils.toString(request.getInputStream(), "UTF-8");// 第二次读取
// 场景一:(抛出异常:Stream closed)
String body2 = IOUtils.toString(request.getInputStream(), "UTF-8");
// 场景二:Controller层的@RequestBody直接报错 org.springframework.http.converter.HttpMessageNotReadableException: Required request body is missing: ...

解决方案:缓存请求体

我们可以通过自定义 HttpServletRequestWrapper 来缓存请求体,使得它可以被多次读取。

1. 实现 RequestWrapper

import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.*;public class RequestWrapper extends HttpServletRequestWrapper {//参数字节数组@Getterprivate byte[] requestBody;//Http请求对象private final HttpServletRequest request;public RequestWrapper(HttpServletRequest request) throws IOException {super(request);this.request = request;}@Overridepublic ServletInputStream getInputStream() throws IOException {/*每次调用此方法时将数据流中的数据读取出来,然后再回填到InputStream之中解决通过@RequestBody和@RequestParam(POST方式)读取一次后控制器拿不到参数问题*/if (null == this.requestBody) {ByteArrayOutputStream baos = new ByteArrayOutputStream();IOUtils.copy(request.getInputStream(), baos);this.requestBody = baos.toByteArray();}final ByteArrayInputStream bais = new ByteArrayInputStream(requestBody);return new ServletInputStream() {@Overridepublic boolean isFinished() {return false;}@Overridepublic boolean isReady() {return false;}@Overridepublic void setReadListener(ReadListener listener) {}@Overridepublic int read() {return bais.read();}};}@Overridepublic BufferedReader getReader() throws IOException {return new BufferedReader(new InputStreamReader(this.getInputStream()));}
}

2. 使用 RequestWrapper

在 Filter 中包装原始请求:

@Component
@Order(Ordered.HIGHEST_PRECEDENCE)	// 最高优先级
public class RequestCachingFilter implements Filter {@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)throws IOException, ServletException {// 包装原始请求RequestWrapper wrappedRequest = new RequestWrapper((HttpServletRequest) request);// 注意这里传的是request的装饰类 RequestWrapper chain.doFilter(wrappedRequest, response);}
}

方案优势

  1. 性能优化:只在构造时读取一次请求体,后续从缓存读取
  2. 线程安全:每个请求有自己的包装实例,互不干扰
  3. 兼容性:完全兼容 HttpServletRequest 的所有方法
  4. 灵活性:可以随时获取原始请求体数据

注意事项

  1. 大文件处理:对于大文件上传,缓存整个请求体可能消耗较多内存
  2. 流式处理:如果确实需要流式处理大数据,不宜使用此方案
  3. Filter 顺序:确保此 Filter 在其他需要读取请求体的 Filter 之前执行
http://www.dtcms.com/a/509960.html

相关文章:

  • c2c网站建设实例石家庄58同城
  • 网站色彩搭配网站后台ftp在哪
  • 如何免费注册自己的网站郴州seo推广
  • 广州传业建设有限公司网站wordpress related posts 汉化
  • 汇编语言做网站淮安网站设计
  • 前端兼职一个静态页面报价seo工具包括
  • 晋中住房保障和城乡建设局网站中国网站用Cn域名
  • 开个送快餐网站怎么做frontpage导入网站
  • html成品网站wordpress 评论 html代码
  • wordpress 是什么开源协议厦门seo哪家强
  • 个人做网站 需要学什么只是seo网站排名优化教程
  • 网站开发培训学校网站网站建设终身不用维护
  • 企业网站首页的实现手机wordpress教程
  • 南山区网站建设公司免费搭建个人网站的3种实用方法
  • 网站的k线图怎么做几十元做网站
  • 企联网站建设wordpress详情页的百度搜索出图
  • 信阳市两学一做网站o2o网站制作
  • 怎么增加网站反链iis 网站压缩
  • 进网站后台加什么设建网站
  • 中国钣金加工网网络优化基础知识
  • 网站商品支付怎么做一级域名的网站制作
  • 怎么开发自己的网站票务网站开发
  • 阿里巴巴免费做网站网站建设步骤与时间表
  • 网站显示wordpress内容营销的方法
  • 在putty做网站要拷贝什么网站创建设计SEO优化象客
  • 做网站空间商需要办什么手续手机评测哪个网站做的好点
  • 微信公众号自己微网站吗seo交流qq群
  • 软件工作室网站模板网站建设主要推广方式
  • 网络公司网站模板返利网站做鹊桥推广
  • 宁夏建设银行发行寄念币网站山东网站备案号