日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

解决在Filter中读取Request中的流后,后续controller或restful接口中无法获取流的问题

發(fā)布時間:2024/3/13 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 解决在Filter中读取Request中的流后,后续controller或restful接口中无法获取流的问题 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.


首先我們來描述一下在開發(fā)中遇到的問題,場景如下:


比如我們要攔截所有請求,獲取請求中的某個參數(shù),進(jìn)行相應(yīng)的邏輯處理:比如我要獲取所有請求中的公共參數(shù) token,clientVersion等等;這個時候我們通常有兩種做法

?前提條件是我們實(shí)現(xiàn)Filter類,重寫doFilter方法


1、通過getParameter方法獲得

? ? ? HttpServletRequest hreq = (HttpServletRequest) req;

? ? ? String param = hreq.getParameter("param");

這種方法有缺陷:它只能獲取 ?POST 提交方式中的 ?

Content-Type: application/x-www-form-urlencoded;

? ? 這種提交方式中,key為param ,若提交類型不是這種方式就獲取不到param的值


2、獲取請求對象中的數(shù)據(jù)流,通過解析流信息來獲取提交的內(nèi)容;代碼示例如下:

/*** 獲取請求Body** @param request* @return*/public static String getBodyString(ServletRequest request) {StringBuilder sb = new StringBuilder();InputStream inputStream = null;BufferedReader reader = null;try {inputStream = 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();}
通過這種簡單的解析方式,將http請求中的body解析成 字符串的形式;然后再對字符串的格式進(jìn)行業(yè)務(wù)解析;

這種處理方式的優(yōu)點(diǎn)是:能解析 出content-Type 為 ?application/x-www-form-urlencoded ,application/json , text/xml 這三種提交方式的 數(shù)據(jù) (至于另外一種帶文件的請求:multipart/form-data ,本人沒有親自測試過,等后期遇到此類為題再來解決)。 上述方法返回的可能是key,value(對應(yīng)第一種content-type),可能是json字符串(對應(yīng)第二種),可能是xml的字符串(對應(yīng)第三種)

但是這種方式有一個很大的缺點(diǎn):那就是當(dāng)從請求中獲取流以后,流被filter中的這個?inputStreamToString(InputStream in) 這個方法處理后就被“消耗”了,這會導(dǎo)致,chain.doFilter(request, res)這個鏈在傳遞 request對象的時候,里面的請求流為空,導(dǎo)致責(zé)任鏈模式下,其他下游的鏈無法獲取請求的body,從而導(dǎo)致程序無法正常運(yùn)行,這也使得我們的這個filter雖然可以獲取請求信息,但是它會導(dǎo)致整個應(yīng)用程序不可用,那么它也就失去了意義;

? ? 針對第二種方式的缺陷:流一旦被讀取,就無法向下傳遞整個問題,有如下解決方案;

? ? 解決思路如下:將取出來的字符串,再次轉(zhuǎn)換成流,然后把它放入到新request 對象中,在chain.doFiler方法中 傳遞新的request對象;要實(shí)現(xiàn)這種思路,需要自定義一個類

繼承HttpServletRequestWrapper,然后重寫public BufferedReader getReader()方法,public ?ServletInputStream getInputStream()方法;(這兩個方法的重寫實(shí)現(xiàn)邏輯如下:getInputStream()方法中將body體中的字符串轉(zhuǎn)換為字節(jié)流(它實(shí)質(zhì)上返回的是一個ServletInputStream 對象);然后通過getReader()調(diào)用---->getInputStream()方法;),繼承實(shí)現(xiàn)重寫邏輯以后,在自定義分filter(VersionCheckFilter)中,使用自定義的HttpServletRequestWrapper(BodyReaderHttpServletRequestWrapper)將原始的HttpServletRequest對象進(jìn)行再次封裝;再通過BodyReaderHttpServletRequestWrapper對象去做dofilter(req,res)的req對象;

? ?涉及的三個類的代碼如下:

? ?自定義的HttpServletRequestWrapper

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.ServletInputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper;import com.yt.util.HttpHelper;public class BodyReaderHttpServletRequestWrapper extendsHttpServletRequestWrapper {private final byte[] body;public BodyReaderHttpServletRequestWrapper(HttpServletRequest request) throws IOException {super(request);System.out.println("-------------------------------------------------"); Enumeration e = request.getHeaderNames() ; while(e.hasMoreElements()){ String name = (String) e.nextElement(); String value = request.getHeader(name); System.out.println(name+" = "+value); } body = HttpHelper.getBodyString(request).getBytes(Charset.forName("UTF-8"));}@Overridepublic BufferedReader getReader() throws IOException {return new BufferedReader(new InputStreamReader(getInputStream()));}@Overridepublic ServletInputStream getInputStream() throws IOException {final ByteArrayInputStream bais = new ByteArrayInputStream(body);return new ServletInputStream() {@Overridepublic int read() throws IOException {return bais.read();}};}@Overridepublic String getHeader(String name) {return super.getHeader(name);}@Overridepublic Enumeration<String> getHeaderNames() {return super.getHeaderNames();}@Overridepublic Enumeration<String> getHeaders(String name) {return super.getHeaders(name);}}

?2、輔助類

HttpHelper

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 {/*** 獲取請求Body** @param request* @return*/public static String getBodyString(ServletRequest request) {StringBuilder sb = new StringBuilder();InputStream inputStream = null;BufferedReader reader = null;try {inputStream = 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();} }
3、自定義的filter

import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; import java.net.URL; import java.net.URLDecoder; import java.util.Map;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; import javax.xml.crypto.URIDereferencer;import com.yt.util.HttpHelper; import com.yt.util.JsonHelper;public class VersionCheckFilter implements Filter {@Overridepublic void destroy() {}@Overridepublic void doFilter(ServletRequest req, ServletResponse res,FilterChain chain) throws IOException, ServletException {HttpServletRequest hreq = (HttpServletRequest) req;String uri = hreq.getRequestURI();if(uri.contains("uploadImageServlet")){//圖像上傳的請求,不做處理chain.doFilter(req, res);}else{String reqMethod = hreq.getMethod();if("POST".equals(reqMethod)){PrintWriter out = null; HttpServletResponse response = (HttpServletResponse) res;response.setCharacterEncoding("UTF-8"); response.setContentType("application/json; charset=utf-8"); /* String requestStr = this.inputStreamToString(hreq.getInputStream());String[] arrs = requestStr.split("&"); for (String strs : arrs) {String[] strs2 = strs.split("=");for (int i = 0; i < strs2.length; i++) {if (strs2[0].equals("param")) {if (strs2[1] != null &&!strs2[1].equals("")) {System.out.println("test=" + strs2[1]);}}}}*/ServletRequest requestWrapper = new BodyReaderHttpServletRequestWrapper(hreq);String body = HttpHelper.getBodyString(requestWrapper);//如果是POST請求則需要獲取 param 參數(shù)String param = URLDecoder.decode(body,"utf-8");//String param = hreq.getParameter("param");//json串 轉(zhuǎn)換為Mapif(param!=null&?m.contains("=")){param = param.split("=")[1];}Map paramMap = JsonHelper.getGson().fromJson(param, Map.class);Object obj_clientversion = paramMap.get("clientVersion");String clientVersion = null;if(obj_clientversion != null){clientVersion = obj_clientversion.toString();System.out.println(clientVersion);/*try { out = response.getWriter();Map remap = new HashMap<String, Object>();remap.put("code", 9);remap.put("message", Constant.SYSTEM_ERR_DESC);out.append(JsonHelper.getGson().toJson(remap)); } catch (IOException e) { e.printStackTrace(); } finally { if (out != null) { out.close(); } }*/chain.doFilter(requestWrapper, res); }else{chain.doFilter(requestWrapper, res); }}else{//get請求直接放行chain.doFilter(req, res);}}}@Overridepublic void init(FilterConfig arg0) throws ServletException {}/*public String inputStreamToString(InputStream in) throws IOException {StringBuffer out = new StringBuffer();byte[] b = new byte[4096];for (int n; (n = in.read(b)) != -1;) {out.append(new String(b, 0, n));}return out.toString();}*/ }


??



總結(jié)

以上是生活随笔為你收集整理的解决在Filter中读取Request中的流后,后续controller或restful接口中无法获取流的问题的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。