解读HttpServletRequestWrapper处理request数据流多次读取问题
本次讨论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()); } @Override public 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; } @Override public int read() throws IOException { return inputStream.read(); } @Override public boolean isFinished() { return false; } @Override public boolean isReady() { return false; } @Override public void setReadListener(ReadListener readListener) { } } @Override public 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\"]"; @Override public 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; } @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 { } /** * 获取用户请求的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>
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。
相关文章
spring通过filter,Interceptor统一处理ResponseBody的返回值操作
这篇文章主要介绍了spring通过filter,Interceptor统一处理ResponseBody的返回值操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧2020-09-09如何解决idea的Translation插件google翻译无法使用问题
这篇文章主要介绍了如何解决idea的Translation插件google翻译无法使用问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教2024-05-05Springboot集成spring data elasticsearch过程详解
这篇文章主要介绍了springboot集成spring data elasticsearch过程详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下2020-04-04使用Kubernetes和Docker部署Java微服务详细代码
Java微服务项目是一种基于Java技术栈的分布式系统开发方式,下面这篇文章主要给大家介绍了关于使用Kubernetes和Docker部署Java微服务的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下2024-07-07springboot中使用mybatisplus自带插件实现分页的示例代码
这篇文章主要介绍了springboot中使用mybatisplus自带插件实现分页,本文通过示例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下2022-09-09
最新评论