關(guān)于Filter中獲取請(qǐng)求體body后再次讀取的問(wèn)題
Filter獲取請(qǐng)求體body再次讀取
工作需要,要將請(qǐng)求和響應(yīng)做一些處理,寫(xiě)一個(gè)filter攔截請(qǐng)求,攔截request中body內(nèi)容后,字符流關(guān)閉,controller取到的請(qǐng)求體內(nèi)容為空。
從Request中獲取輸入流,InputStream只能被讀取一次。
解決方案
給request添加一個(gè)包裝類BodyWrapper,繼承HttpServletRequestWrapper,
先從request中取輸入流,讀取流中的數(shù)據(jù),然后重寫(xiě)getInputStream()和getReader()方法。
chain.doFilter(requestWrapper, response);
import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStreamReader; import java.nio.charset.Charset; import java.util.Enumeration; import javax.servlet.ReadListener; import javax.servlet.ServletInputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; import com.xera.fsafesso.HttpHelper; public class BodyWrapper extends HttpServletRequestWrapper {undefined ? ? private final byte[] body; ? ? public BodyWrapper(HttpServletRequest request) throws IOException {undefined ? ? ? ? super(request); ? ? ? ? body = HttpHelper.getBodyString(request).getBytes(Charset.forName("UTF-8")); ? ? } ? ? @Override ? ? public BufferedReader getReader() throws IOException {undefined ? ? ? ? return new BufferedReader(new InputStreamReader(getInputStream())); ? ? } ? ? @Override ? ? public ServletInputStream getInputStream() throws IOException {undefined ? ? ? ? final ByteArrayInputStream bais = new ByteArrayInputStream(body); ? ? ? ? return new ServletInputStream(){undefined ? ? ? ? ? ? @Override ? ? ? ? ? ? public int read() throws IOException {undefined ? ? ? ? ? ? ? ? return bais.read(); ? ? ? ? ? ? } ? ? ? ? ? ? @Override ? ? ? ? ? ? public boolean isFinished() {undefined ? ? ? ? ? ? ? ? return false; ? ? ? ? ? ? } ? ? ? ? ? ? @Override ? ? ? ? ? ? public boolean isReady() {undefined ? ? ? ? ? ? ? ? return false; ? ? ? ? ? ? } ? ? ? ? ? ? @Override ? ? ? ? ? ? public void setReadListener(ReadListener arg0) {undefined ? ? ? ? ? ? } ? ? ? ? }; ? ? } ? ? @Override ? ? public String getHeader(String name) {undefined ? ? ? ? return super.getHeader(name); ? ? } ? ? @Override ? ? public Enumeration<String> getHeaderNames() {undefined ? ? ? ? return super.getHeaderNames(); ? ? } ? ? @Override ? ? public Enumeration<String> getHeaders(String name) {undefined ? ? ? ? return super.getHeaders(name); ? ? } }
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.nio.charset.Charset; import javax.servlet.ServletRequest; public class HttpHelper {undefined ? ? ?/** ? ? ?* 獲取請(qǐng)求Body ? ? ?* @param request ? ? ?* @return ? ? ?*/ ? ? public static String getBodyString(ServletRequest request) {undefined ? ? ? ? StringBuilder sb = new StringBuilder(); ? ? ? ? InputStream inputStream = null; ? ? ? ? BufferedReader reader = null; ? ? ? ? try {undefined ? ? ? ? ? ? inputStream = request.getInputStream(); ? ? ? ? ? ? reader = new BufferedReader(new InputStreamReader(inputStream, Charset.forName("UTF-8"))); ? ? ? ? ? ? String line = ""; ? ? ? ? ? ? while ((line = reader.readLine()) != null) {undefined ? ? ? ? ? ? ? ? sb.append(line); ? ? ? ? ? ? } ? ? ? ? } catch (IOException e) {undefined ? ? ? ? ? ? e.printStackTrace(); ? ? ? ? } finally {undefined ? ? ? ? ? ? if (inputStream != null) {undefined ? ? ? ? ? ? ? ? try {undefined ? ? ? ? ? ? ? ? ? ? inputStream.close(); ? ? ? ? ? ? ? ? } catch (IOException e) {undefined ? ? ? ? ? ? ? ? ? ? e.printStackTrace(); ? ? ? ? ? ? ? ? } ? ? ? ? ? ? } ? ? ? ? ? ? if (reader != null) {undefined ? ? ? ? ? ? ? ? try {undefined ? ? ? ? ? ? ? ? ? ? reader.close(); ? ? ? ? ? ? ? ? } catch (IOException e) {undefined ? ? ? ? ? ? ? ? ? ? e.printStackTrace(); ? ? ? ? ? ? ? ? } ? ? ? ? ? ? } ? ? ? ? } ? ? ? ? return sb.toString(); ? ? } }
Filter中寫(xiě)法如下:
HttpServletRequest httpServletRequest = (HttpServletRequest) request; ? ? ? ? ? ? Map<String, String> requestMap = this.getTypesafeRequestMap(httpServletRequest); ? ? ? ? ? ? requestWrapper = new BodyWrapper(httpServletRequest); ? ? ? ? ? ? String body = HttpHelper.getBodyString(requestWrapper); ? ? ? ? ? ? log.info("loggingFilter---請(qǐng)求路徑 {},請(qǐng)求參數(shù) {},請(qǐng)求體內(nèi)容 {}",httpServletRequest.getRequestURL(),requestMap,body); ? ? ? chain.doFilter(requestWrapper, response);
在使用注解的方式(即@WebFilter)聲明過(guò)濾器時(shí),
需要再main函數(shù)類上添加@ServletComponentScan(basePackages = "此處寫(xiě)明類地址,格式為包名+類名(如com.*)
Http請(qǐng)求解決body流一旦被讀取了就無(wú)法二次讀取情況
相信大家在工作當(dāng)中,經(jīng)常會(huì)遇到需要處理http請(qǐng)求及響應(yīng)body的場(chǎng)景,這里最大的問(wèn)題應(yīng)該就是body中流以但被讀取就無(wú)法二次讀取了。
解決request請(qǐng)求流只能讀取一次的問(wèn)題
我們編寫(xiě)一個(gè)過(guò)濾器,這樣就可以重寫(xiě)body了
package com.interceptor; import java.io.IOException; import java.util.Arrays; import java.util.List; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class MyFilter implements Filter { private static String privateKey ; public String getPrivateKey() { return privateKey; } public void setPrivateKey(String key) { privateKey = key; } /** * 排除過(guò)濾路徑 */ List<String> ignore = Arrays.asList("/xxxx"); /** * 前綴排除 如 /static/goods 排除 */ List<String> ignorePrefix = Arrays.asList( "/css/", "/pop/", "/js/", "/static/", "/images/", "/favicon.ico"); /** * 排除過(guò)濾路徑 */ List<String> ignoreSuffix = Arrays.asList("/test"); @Override public void init(FilterConfig filterConfig) throws ServletException { //過(guò)濾器初始化 } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { // 防止流讀取一次后就沒(méi)有了, 所以需要將流繼續(xù)寫(xiě)出去 HttpServletRequest request = (HttpServletRequest) servletRequest; HttpServletResponse response = (HttpServletResponse) servletResponse; String uri = request.getServletPath(); response.setContentType("application/json;charset=UTF-8"); ServletRequest requestWrapper = null; if(canIgnore(uri)) { requestWrapper = new MyFilterBodyReaderHttpServletRequestWrapper(request); filterChain.doFilter(requestWrapper, response); return; } try { requestWrapper = new MyFilterBodyReaderHttpServletRequestWrapper(request, response, privateKey); } catch (Exception e) { e.printStackTrace(); return; } filterChain.doFilter(requestWrapper, servletResponse); } @Override public void destroy() { //過(guò)濾器銷毀 } private boolean canIgnore(String uri) { logger.info("過(guò)濾器 request uri : {} ",uri); boolean isExcludedPage = false; for (String page : ignore) { if (uri.equals(page)) { logger.info("請(qǐng)求路徑不需要攔截,忽略該uri : {} ",uri); isExcludedPage = true; break; } } for (String prefix : ignorePrefix) { if (uri.startsWith(prefix)) { logger.info("請(qǐng)求路徑前綴[{}],不攔截該uri : {} ", prefix, uri); isExcludedPage = true; break; } } for (String prefix : ignoreSuffix) { if (uri.endsWith(prefix)) { logger.info("請(qǐng)求路徑后綴[{}],不攔截該uri : {} ", prefix, uri); isExcludedPage = true; break; } } return isExcludedPage; } }
package com.interceptor; import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.nio.charset.Charset; import java.util.Map; import javax.servlet.ReadListener; import javax.servlet.ServletInputStream; import javax.servlet.ServletRequest; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; import javax.servlet.http.HttpServletResponse; import com.alibaba.fastjson.JSON; /** * @Description: TODO 過(guò)濾器處理requestbody獲取一次就失效 */ public class MyFilterBodyReaderHttpServletRequestWrapper extends HttpServletRequestWrapper { private final byte[] body; /** * TODO 重寫(xiě)requestbody * @param request * @throws IOException */ public MyFilterBodyReaderHttpServletRequestWrapper(HttpServletRequest request) throws IOException { super(request); String sessionStream = getBodyString(request); body = sessionStream.getBytes(Charset.forName("UTF-8")); } /** * TODO 攔截解密,校驗(yàn),重寫(xiě)requestbody */ @SuppressWarnings({ "rawtypes", "unchecked" }) public MyFilterBodyReaderHttpServletRequestWrapper(HttpServletRequest request,HttpServletResponse response, String clientKey, Boolean ignoreCheckSign) throws Exception { super(request); String sessionStream = getBodyString(request); Map paramMap = (Map) JSON.parse(sessionStream); /** *自己項(xiàng)目中與合作方的加解密內(nèi)容 *如:String data= (String) paramMap.get("data"); * String json=xxxxxutil.decrypt(參數(shù)); */ body = json.getBytes(Charset.forName("UTF-8")); } /** * TODO 獲取請(qǐng)求Body * @param request * @return * @throws */ public String getBodyString(final ServletRequest request) { StringBuilder sb = new StringBuilder(); InputStream inputStream = null; BufferedReader reader = null; try { inputStream = cloneInputStream(request.getInputStream()); reader = new BufferedReader(new InputStreamReader(inputStream, Charset.forName("UTF-8"))); String line = ""; while ((line = reader.readLine()) != null) { sb.append(line); } } catch (IOException e) { e.printStackTrace(); } finally { if (inputStream != null) { try { inputStream.close(); } catch (IOException e) { e.printStackTrace(); } } if (reader != null) { try { reader.close(); } catch (IOException e) { e.printStackTrace(); } } } return sb.toString(); } /** * TODO 無(wú)參獲取請(qǐng)求Body * @return * @throws */ public String getBodyString() { if (body == null) { return null; } String str = new String(body); return str; } /** * TODO 復(fù)制輸入流 * @param inputStream * @return * @throws */ public InputStream cloneInputStream(ServletInputStream inputStream) { ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int len; try { while ((len = inputStream.read(buffer)) > -1) { byteArrayOutputStream.write(buffer, 0, len); } byteArrayOutputStream.flush(); } catch (IOException e) { e.printStackTrace(); } InputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray()); return byteArrayInputStream; } @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 boolean isFinished() { return false; } @Override public boolean isReady() { return false; } @Override public void setReadListener(ReadListener readListener) { } }; } }
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
簡(jiǎn)單實(shí)現(xiàn)Servlet文件下載功能
這篇文章主要教大家如何簡(jiǎn)單實(shí)現(xiàn)Servlet文件下載功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-09-09SpringBoot+MybatisPlus+代碼生成器整合示例
這篇文章主要介紹了SpringBoot+MybatisPlus+代碼生成器整合示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-03-03SpringBoot深入分析講解監(jiān)聽(tīng)器模式上
監(jiān)聽(tīng)器模式,大家應(yīng)該并不陌生,主要的組成要素包括了事件、監(jiān)聽(tīng)器以及廣播器;當(dāng)事件發(fā)生時(shí),廣播器負(fù)責(zé)將事件傳遞給所有已知的監(jiān)聽(tīng)器,而監(jiān)聽(tīng)器會(huì)對(duì)自己感興趣的事件進(jìn)行處理2022-07-07Maven在Java8下如何忽略Javadoc的編譯錯(cuò)誤詳解
這篇文章主要給大家介紹了關(guān)于Maven在Java8下如何忽略Javadoc的編譯錯(cuò)誤的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2018-08-08Java實(shí)現(xiàn)斷點(diǎn)續(xù)傳功能的示例代碼
這篇文章主要為大家詳細(xì)介紹了如何利用Java語(yǔ)言實(shí)現(xiàn)網(wǎng)絡(luò)資源的斷點(diǎn)續(xù)傳功能,文中的示例代碼講解詳細(xì),具有一定的學(xué)習(xí)價(jià)值,感興趣的可以了解一下2022-10-10