關(guān)于Filter中獲取請求體body后再次讀取的問題
Filter獲取請求體body再次讀取
工作需要,要將請求和響應(yīng)做一些處理,寫一個filter攔截請求,攔截request中body內(nèi)容后,字符流關(guān)閉,controller取到的請求體內(nèi)容為空。
從Request中獲取輸入流,InputStream只能被讀取一次。
解決方案
給request添加一個包裝類BodyWrapper,繼承HttpServletRequestWrapper,
先從request中取輸入流,讀取流中的數(shù)據(jù),然后重寫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
? ? ?/**
? ? ?* 獲取請求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中寫法如下:
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
? ? ? ? ? ? Map<String, String> requestMap = this.getTypesafeRequestMap(httpServletRequest);
? ? ? ? ? ? requestWrapper = new BodyWrapper(httpServletRequest);
? ? ? ? ? ? String body = HttpHelper.getBodyString(requestWrapper);
? ? ? ? ? ? log.info("loggingFilter---請求路徑 {},請求參數(shù) {},請求體內(nèi)容 {}",httpServletRequest.getRequestURL(),requestMap,body);
? ? ? chain.doFilter(requestWrapper, response);在使用注解的方式(即@WebFilter)聲明過濾器時,
需要再main函數(shù)類上添加@ServletComponentScan(basePackages = "此處寫明類地址,格式為包名+類名(如com.*)
Http請求解決body流一旦被讀取了就無法二次讀取情況
相信大家在工作當中,經(jīng)常會遇到需要處理http請求及響應(yīng)body的場景,這里最大的問題應(yīng)該就是body中流以但被讀取就無法二次讀取了。
解決request請求流只能讀取一次的問題
我們編寫一個過濾器,這樣就可以重寫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;
}
/**
* 排除過濾路徑
*/
List<String> ignore = Arrays.asList("/xxxx");
/**
* 前綴排除 如 /static/goods 排除
*/
List<String> ignorePrefix = Arrays.asList( "/css/", "/pop/", "/js/", "/static/", "/images/", "/favicon.ico");
/**
* 排除過濾路徑
*/
List<String> ignoreSuffix = Arrays.asList("/test");
@Override
public void init(FilterConfig filterConfig) throws ServletException {
//過濾器初始化
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
// 防止流讀取一次后就沒有了, 所以需要將流繼續(xù)寫出去
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() {
//過濾器銷毀
}
private boolean canIgnore(String uri) {
logger.info("過濾器 request uri : {} ",uri);
boolean isExcludedPage = false;
for (String page : ignore) {
if (uri.equals(page)) {
logger.info("請求路徑不需要攔截,忽略該uri : {} ",uri);
isExcludedPage = true;
break;
}
}
for (String prefix : ignorePrefix) {
if (uri.startsWith(prefix)) {
logger.info("請求路徑前綴[{}],不攔截該uri : {} ", prefix, uri);
isExcludedPage = true;
break;
}
}
for (String prefix : ignoreSuffix) {
if (uri.endsWith(prefix)) {
logger.info("請求路徑后綴[{}],不攔截該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 過濾器處理requestbody獲取一次就失效
*/
public class MyFilterBodyReaderHttpServletRequestWrapper extends HttpServletRequestWrapper {
private final byte[] body;
/**
* TODO 重寫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 攔截解密,校驗,重寫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);
/**
*自己項目中與合作方的加解密內(nèi)容
*如:String data= (String) paramMap.get("data");
* String json=xxxxxutil.decrypt(參數(shù));
*/
body = json.getBytes(Charset.forName("UTF-8"));
}
/**
* TODO 獲取請求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 無參獲取請求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) {
}
};
}
} 以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
SpringBoot+MybatisPlus+代碼生成器整合示例
這篇文章主要介紹了SpringBoot+MybatisPlus+代碼生成器整合示例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-03-03
Maven在Java8下如何忽略Javadoc的編譯錯誤詳解
這篇文章主要給大家介紹了關(guān)于Maven在Java8下如何忽略Javadoc的編譯錯誤的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2018-08-08

