JSON 数据读一次就没了,怎么办?
对于前端传来的怎么办 JSON 数据,我们在服务端基本上都是数据通过 IO 流来解析,如果是读次古老的 Servlet,那么我们直接解析 IO 流;如果是怎么办在 SpringMVC 中,我们往往通过 @RequestBody 注解来解析。数据
如果通过 IO 流来解析参数,读次默认情况下,怎么办IO 流读一次就结束了,数据就没有了。读次而往往有些场景,怎么办需要我们多次读取参数,数据我举一个例子:
接口幂等性的读次处理,同一个接口,怎么办在短时间内接收到相同参数的数据请求,接口可能会拒绝处理。读次那么在判断的时候,就需要先把请求的参数提取出来进行判断,如果是 JSON 参数,此时就会有问题,参数提前取出来了,将来在接口中再去获取 JSON 参数,WordPress模板就会发现没有了。
我们来看看这个问题怎么解决,这也是最近松哥在做的 TienChin 项目的一个小知识点,和大家分享下。
新建一个 Spring Boot 项目,引入 Web 依赖,我们一起来看下面的问题。
1. 问题演示假设我现在有一个处理接口幂等性的拦截器,在这个拦截器中,我需要先获取到请求的参数,然后进行比对等等,我这里先简单模拟一下,比如我们项目中有如下拦截器:
public class IdempotenceInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String s = request.getReader().readLine();
System.out.println("s = " + s);
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
}
}在这个拦截器中先把请求的参数拎出来,瞅一眼。通过 IO 流读取出来的参数最大特点是一次性,也就是读一次就失效了。
然后我们配置一下这个拦截器:
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new IdempotenceInterceptor()).addPathPatterns("/**");
}
}最后再来看看 Controller 接口:
@RestController
public class HelloController {
@PostMapping("/hello")
public void hello(@RequestBody String msg) throws IOException {
System.out.println("msg = " + msg);
}
}在接口参数上我们加了 @RequestBody 注解,这个底层也是通过 IO 流来读取数据的,亿华云但是由于 IO 流在拦截器中已经被读取过一次了,所以到了接口中再去读取就会出错。报错信息如下:

然而很多时候,我们希望 IO 流能够被多次读取,那么怎么办呢?
2. 问题解决这里我们可以利用装饰者模式对 HttpServletRequest 的功能进行增强,具体做法也很简单,我们重新定义一个 HttpServletRequest:
public class RepeatedlyRequestWrapper extends HttpServletRequestWrapper {
private final byte[] body;
public RepeatedlyRequestWrapper(HttpServletRequest request, ServletResponse response) throws IOException {
super(request);
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");
body = request.getReader().readLine().getBytes("UTF-8");
}
@Override
public BufferedReader getReader() throws IOException {
return new BufferedReader(new InputStreamReader(getInputStream()));
}
@Override
public ServletInputStream getInputStream() throws IOException {
final ByteArrayInputStream bais = new ByteArrayInputStream(body);
return new ServletInputStream() {
@Override
public int read() throws IOException {
return bais.read();
}
@Override
public int available() throws IOException {
return body.length;
}
@Override
public boolean isFinished() {
return false;
}
@Override
public boolean isReady() {
return false;
}
@Override
public void setReadListener(ReadListener readListener) {
}
};
}
}这段代码并不难,很好懂。
首先在构造 RepeatedlyRequestWrapper 的时候,就通过 IO 流将数据读取出来并存入到一个 byte 数组中,然后重写 getReader 和 getInputStream 方法,在这两个读取 IO 流的方法中,都从 byte 数组中返回 IO 流数据出来,这样就实现了反复读取了。
接下来我们定义一个过滤器,让这个装饰后的 Request 生效:
public class RepeatableFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
ServletRequest requestWrapper = null;
if (request instanceof HttpServletRequest
&& StringUtils.startsWithIgnoreCase(request.getContentType(), MediaType.APPLICATION_JSON_VALUE)) {
requestWrapper = new RepeatedlyRequestWrapper((HttpServletRequest) request, response);
}
if (null == requestWrapper) {
chain.doFilter(request, response);
} else {
chain.doFilter(requestWrapper, response);
}
}
@Override
public void destroy() {
}
}判断一下,如果请求数据类型是 JSON 的话,就把 HttpServletRequest “偷梁换柱”改为 RepeatedlyRequestWrapper,然后让过滤器继续往下走。
最后再配置一下这个过滤器:
@Bean
FilterRegistrationBean
FilterRegistrationBean
bean.addUrlPatterns("/*");
bean.setFilter(new RepeatableFilter());
return bean;
}好啦大功告成。
以后,我们的 JSON 数据就可以通过 IO 流反复读取了。高防服务器
相关文章
电脑字体涂鸦教程大全(打造个性化艺术作品,解锁电脑字体涂鸦的无限可能)
摘要:随着电脑技术的不断发展,电脑字体涂鸦成为了一种新兴的艺术形式,它将传统的手写涂鸦与电脑字体相结合,为我们呈现了更加多样化的创作方式。本文将为您介绍一份完整的电脑字体涂鸦教程大全,从...2025-11-04
怎么清除windows 7搜索记录 windows 7搜索历史记录删除教程
Windows 7的搜索功能非常强大,也很智能,在搜索资料后,在搜索栏中会留下记录,这样就有可能会泄露个人隐私,因此搜索后,最好不要保留搜索记录,以免留下后患。删除搜索记录在资源管理器的搜索窗口中并没2025-11-04
Windows 7是由微软公司Microsoft)开发的操作系统,核心版本号为Windows NT 6.1。Windows 7可供家庭及商业工作环境、笔记本电脑、平板电脑、多媒体中心等使用。 Wind2025-11-04
windows 7系统快速批量修改MP3音乐信息无需借助第三方工具
快速批量修改Windows 7系统MP3音乐信息的方法分享给大家,MP3是Internet上最流行的音乐格式,它的体积小和音质佳伸手用户们的喜欢,mp3音乐除了有歌曲的名称之外,还会附带歌手以及专辑等2025-11-04网络设置中缺少WLAN选项的解决方法(如何解决设备中找不到WLAN选项的问题)
摘要:随着互联网的普及,网络已经成为我们日常生活和工作中必不可少的一部分。然而,有时候我们可能会遇到设备中缺少WLAN选项的问题,这将导致我们无法连接到无线网络,给我们的生活和工作带来诸...2025-11-04
大家电脑上或多或少都有着自己的隐私,别人在使用自己电脑的时候,又不希望别人看到自己的隐私,有什么办法可以隐藏这些隐私文件夹吗?当然有,今天小编就教大家如何在系统里隐藏文件夹。一、把文件夹设置成隐藏属性2025-11-04

最新评论