解讀HttpServletRequestWrapper處理request數(shù)據(jù)流多次讀取問(wèn)題
本次討論post方式獲取參數(shù),request.getInputStream()獲取一次以后不能第二次獲取,以及request.getParameter()與request.getInputStream()也存在這種情況
一、獲取請(qǐng)求參數(shù)
- 1、request.getParameter()
- 2、request.getInputStream()或request.getReader()
二、請(qǐng)求方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()對(duì)應(yīng)application/x-www-form-urlencoded
- 2、request.getInputStream()或request.getReader()對(duì)應(yīng)application/json
那么現(xiàn)在有一個(gè)這樣的需求如果是form表單就獲取formToken然后和緩存的進(jìn)行CRSF防護(hù)
思路根據(jù)上面說(shuō)的form表單參數(shù)獲取分為2大類。
其中request.getInputStream()獲取一次以后不能第二次獲取,以及request.getParameter()與request.getInputStream()也存在這種情況。
- 1、application/x-www-form-urlencoded以及multipart/form-data通過(guò)request.getParameter()獲取
- 2、application/json通過(guò)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 { //保存流中的數(shù)據(jù) 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); //從流中獲取數(shù)據(jù) data = IOUtils.toByteArray(request.getInputStream()); } ? @Override public ServletInputStream getInputStream() throws IOException { //在調(diào)用getInputStream函數(shù)時(shí),創(chuàng)建新的流,包含原先數(shù)據(jù)流中的信息,然后返回 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表單提交校驗(yàn)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 { ? } ? /** * 獲取用戶請(qǐng)求的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>
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Java里的static在Kotlin里如何實(shí)現(xiàn)
這篇文章主要介紹了Java里的static在Kotlin里如何實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-01-01Spring Boot 2結(jié)合Spring security + JWT實(shí)現(xiàn)微信小程序登錄
這篇文章主要介紹了Spring Boot 2結(jié)合Spring security + JWT實(shí)現(xiàn)微信小程序登錄,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-01-01Eclipse中Properties和yml配置文件注釋亂碼的解決
這篇文章主要介紹了Eclipse中Properties和yml配置文件注釋亂碼的解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-10-10SpringBoot權(quán)限認(rèn)證-Sa-Token的使用詳解
Sa-Token是一款輕量級(jí)Java權(quán)限認(rèn)證框架,它簡(jiǎn)化了權(quán)限管理,提高了開(kāi)發(fā)效率,本文通過(guò)實(shí)例介紹了Sa-Token的基本概念、與其他框架的比較、基本語(yǔ)法和高級(jí)用法,并探討了其核心原理和實(shí)際應(yīng)用場(chǎng)景,感興趣的朋友一起看看吧2024-09-09sms4j?2.0?全新來(lái)襲功能的調(diào)整及maven變化詳解
這篇文章主要介紹了sms4j?2.0?全新來(lái)襲功能的調(diào)整及maven變化詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-04-04mybatis plus 自動(dòng)轉(zhuǎn)駝峰配置小結(jié)
SpringBoot提供兩種配置Mybatis的方式,第一種是通過(guò)yml或application.properties文件開(kāi)啟配置,第二種是使用自定義配置類,通過(guò)給容器添加一個(gè)ConfigurationCustomizer來(lái)實(shí)現(xiàn)更靈活的配置,這兩種方法可以根據(jù)項(xiàng)目需求和個(gè)人喜好選擇使用2024-10-10