HttpServletRequestWrapper处理request数据流多次读取问题

news/2025/4/2 15:32:32/

本次讨论post方式获取参数,request.getInputStream()获取一次以后不能第二次获取,以及
request.getParameter()与request.getInputStream()也存在这种情况

一、获取请求参数
1、request.getParameter()
2、request.getInputStream()或request.getReader()
二、请求方contentType
1、application/x-www-form-urlencoded

@RequestMapping("/testWwwFrom")
@ResponseBody
public Book testWwwFrom(Book req, HttpServletRequest servletRequest) {logger.info("查询所有1用户信息" + JSON.toJSONString(req));return req;
}

2、multipart/form-data

@RequestMapping("/testFormData")
@ResponseBody
public Book testFormData(Book req, HttpServletRequest servletRequest) {logger.info("查询所有1用户信息" + JSON.toJSONString(req));return req;
}

3、application/json

@RequestMapping("/testJson")
@ResponseBody
public Book testJsonFrom(@RequestBody Book req, HttpServletRequest servletRequest) {logger.info("查询所有1用户信息" + JSON.toJSONString(req));return req;
}

1、request.getParameter()对应application/x-www-form-urlencoded
2、request.getInputStream()或request.getReader()对应application/json
那么现在有一个这样的需求如果是form表单就获取formToken然后和缓存的进行CRSF防护
思路根据上面说的form表单参数获取分为2大类。
其中request.getInputStream()获取一次以后不能第二次获取,以及
request.getParameter()与request.getInputStream()也存在这种情况。
1、application/x-www-form-urlencoded以及multipart/form-data通过request.getParameter()获取
2、application/json通过request.getInputStream()或request.getReader()获取,这种要依赖HttpServletRequestWrapper

package com.study.ju.web.interceptor;import org.apache.commons.io.IOUtils;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.InputStream;
import java.io.InputStreamReader;
​
/*** <p>https://blog.csdn.net/kaizhangzhang/article/details/97900961</p>** * @version v 0.1 2023/5/29 15:37*/
public class ResettableServletRequestWrapper extends HttpServletRequestWrapper {//保存流中的数据private byte[] data;
​/*** Constructs a request object wrapping the given request.** @param request* @throws IllegalArgumentException if the request is null*/public ResettableServletRequestWrapper(HttpServletRequest request) throws IOException {super(request);//从流中获取数据data = IOUtils.toByteArray(request.getInputStream());}
​@Overridepublic ServletInputStream getInputStream() throws IOException {//在调用getInputStream函数时,创建新的流,包含原先数据流中的信息,然后返回return new NewServletInputStream(new ByteArrayInputStream(data));}
​class NewServletInputStream extends ServletInputStream{private InputStream inputStream;
​public NewServletInputStream(InputStream inputStream){this.inputStream = inputStream;}
​@Overridepublic int read() throws IOException {return inputStream.read();}
​@Overridepublic boolean isFinished() {return false;}
​@Overridepublic boolean isReady() {return false;}
​@Overridepublic void setReadListener(ReadListener readListener) {}}@Overridepublic BufferedReader getReader() throws IOException {return new BufferedReader(new InputStreamReader(this.getInputStream()));}
​
​
}
package com.study.ju.web.interceptor;import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
import java.util.Map;
​
/*** <p>form表单提交校验token</p>** * @version v 0.1 2023/5/29 13:45*/
public class FormSubmitTokenInterceptor implements HandlerInterceptor {
​
​private String formSubmitTokenInterceptorUrls = "[\"/testJson\",\"/test/testJson\",\"/test/testWwwFrom\",\"/test/testRequestParam\"]";
​@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {String requestURI = getRequestURI(request);if ("POST".equals(request.getMethod().toUpperCase()) && StringUtils.isNotEmpty(formSubmitTokenInterceptorUrls)) {List<String> formInterceptorUrls = JSONArray.parseArray(formSubmitTokenInterceptorUrls, String.class);if (CollectionUtils.isNotEmpty(formInterceptorUrls)) {boolean contains = formInterceptorUrls.stream().anyMatch(e -> e.contains(requestURI));if (contains) {String contentType = request.getContentType();System.out.println(contentType);if ("application/json".equalsIgnoreCase(contentType)) {ResettableServletRequestWrapper resettableServletRequestWrapper = new ResettableServletRequestWrapper(request);String bodyParam = IOUtils.toString(resettableServletRequestWrapper.getInputStream());System.out.println(bodyParam);if (StringUtils.isNotEmpty(bodyParam)) {JSONObject jsonObject = JSONObject.parseObject(bodyParam);if (jsonObject.containsKey("formToken")) {String formToken = (String) jsonObject.get("formToken");System.out.println("formToken:"+formToken);}}} else {if (StringUtils.isNotEmpty(request.getParameter("formToken"))) {System.out.println("formToken2:"+request.getParameter("formToken"));}System.out.println("name:"+request.getParameter("name"));}
​
​}}}return true;}
​@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {}
​@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {}
​/*** 获取用户请求的path,不带contextPath* 如:/index.htm*/public static String getRequestURI(HttpServletRequest request) {return StringUtils.replace(request.getRequestURI(), request.getContextPath(), "");}
}

web.xml放在前面

<filter><filter-name>requestFilter</filter-name><filter-class>com.study.ju.web.Filter.HttpServletRequestReplacedFilter</filter-class>
</filter>
<filter-mapping><filter-name>requestFilter</filter-name><url-pattern>/*</url-pattern>
</filter-mapping>

http://www.ppmy.cn/news/116626.html

相关文章

Java的volatile

介绍 volatile volatile 关键字可以说是 Java 虚拟机提供的最轻量级的同步机制&#xff0c;但是它并不容易被正确、完整地理解&#xff0c;以至于许多程序员都习惯去避免使用它&#xff0c;遇到需要处理多线程数据竞争问题的时候一律使用 synchronized 来进行同步。了解 volat…

centos8修改网卡名称成eth0

新安装的centos8网卡名称有时候会变成ensXXX&#xff0c;不太符合以往的习惯&#xff0c;要修改成ethXX并不难&#xff0c;简单记录一下过程。 1.查看现网卡名 [root10-0-200-120 ~]# ifconfig ens3: flags4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500inet 10.0.20…

n5095和n5100哪个好 n5095和n5100区别

n5095采用10纳米制造工艺 四核心4线程 “CPU主频2-2.9GHz 三级缓存4MB 热设计功耗15W内存类型 DDR4 2933MHz&#xff0c;LPDDR4x 2933MHz 选n5100还是n5095这些点很重要http://www.adiannao.cn/dy n5100采用10纳米制造工艺 四核心 “CPU主频1.1-2.8 GHz 三级缓存4MB 热设计功…

诺基亚5800XM

一:关于打电话或来电话黑屏问题,这是因为你有东西遮挡住5800的距离感应器,就在光线感应器和副摄象头的中间,有两个不很明显的小孔,那是距离感应器,任何东西遮挡住它都会在来电话或者打电话时使屏幕黑屏,包括透明的贴膜,所以已经在那个位置贴膜的朋友请把那个位置的贴膜剪去即可…

java之多线程详解(基础版)

1.什么是进程? 1.1进程就是执行程序的一次执行过程,他是应该动态的概念&#xff0c;是系统分资源分配的单位。 2.什么是线程 2.1一个进程中可以包含若干个线程,当然一个进程中至少有一个线程,不然没有存在的意义,线程是CPI调度和执行的单位。 3.创建线程的方式 3.1继承Th…

Clickhouse limit by函数

关注微信公共号&#xff1a;小程在线 关注CSDN博客&#xff1a;程志伟的博客 ClickHouse server version 21.6.6 创建表 dblab-VirtualBox :) CREATE TABLE limit_by(id Int, val Int) ENGINE Memory; CREATE TABLE limit_by ( id Int, val Int ) ENGINE Memory Q…

IPC网络高清摄像机基础知识2(安霸半导体公司产品介绍 “来自2016年”)

需求说明&#xff1a;了解IC供应商安霸公司的产品体系 来自&#xff1a;http://tieba.baidu.com/p/4236056905 一、GoPro的灵魂 -- 安霸半导体公司&#xff08;Ambarella, Inc&#xff09; 一家位于加州SantaClara的初创公司&#xff0c;主营H264压缩处理芯片。说是初创是相…

神舟优雅A550 插入鼠标关闭感应垫

http://down9.zol.com.cn/bijiben/77/TW9ATouchPad.rar?keycb97b66104deecd2c0b4287d18a09202 下载这个感应垫驱动 你就知道怎么设置了