這篇文章主要為大家展示了“SpringBoot過濾器中怎么獲取POST請求的JSON參數”,內容簡而易懂,條理清晰,希望能夠幫助大家解決疑惑,下面讓小編帶領大家一起研究并學習一下“SpringBoot過濾器中怎么獲取POST請求的JSON參數”這篇文章吧。
項目中需要將每個請求的路徑和請求參數以及響應結果,都記錄在日志中,這樣在出現問題時可以快速定位是哪里出現了問題。
當請求來到過濾器時,會有一個Request參數,通過該參數就能獲取到請求路徑和請求參數,以及相關內容
parameterMap = httpRequest.getParameterMap(); String requestMethod = httpRequest.getMethod(); String remoteAddr = httpRequest.getRemoteAddr(); int remotePort = httpRequest.getRemotePort();
上面的getParameterMap(),只能夠獲取到GET請求的參數,如果是POST方法傳的JSON那就沒法獲取到,那如何獲取呢,POST的請求是在請求體body中,而POST請求中的body參數是已流形式存在的
ServletInputStream inputStream = httpRequest.getInputStream();
InputStreamReader reader = new InputStreamReader(inputStream,StandardCharsets.UTF_8);
BufferedReader bfReader = new BufferedReader(reader);
StringBuilder sb = new StringBuilder();
String line;
while ((line = bfReader.readLine()) != null){
sb.append(line);
}
System.out.println(sb.toString());通過上面的方法,我們確實能在過濾器中獲取到POST的JSON參數了,但是按照上面的方法實現的過濾器,我們會發現,當請求經過過濾器來到Controller的時候,請求參數不見了

可以看到,過濾器確實拿到JSON參數,但是接著報了一個request body missing的異常,也就是請求來到Controller時,參數沒有了,這是為啥呢?我們先去源碼看看,Controller平時是怎么拿到請求參數的吧

根據DeBug,可以看到SpringBoot處理請求的最主要的兩個方法是上圖紅框的doService和doDisparch方法,上面就是通過反射去獲取參數名去匹配等

來到invokeForRequest方法,這里面的getMethodArgumentValues,就是SpringBoot獲取請求參數的入口,進入入口后

再經過上面的紅框,就能看到SpringBoot獲取POST請求JSON的參數的真面目了

SpringBoot也是通過獲取request的輸入流來獲取參數,這樣上面的疑問就能解開了,為什么經過過濾器來到Controller請求參數就沒了,這是因為 InputStream read方法內部有一個,postion,標志當前流讀取到的位置,每讀取一次,位置就會移動一次,如果讀到最后,InputStream.read方法會返回-1,標志已經讀取完了,如果想再次讀取,可以調用inputstream.reset方法,position就會移動到上次調用mark的位置,mark默認是0,所以就能從頭再讀了。但是呢 是否能reset又是由markSupported決定的,為true能reset,為false就不能reset,從源碼可以看到,markSupported是為false的,而且一調用reset就是直接異常

所以這也就代表,InputStream只能被讀取一次,后面就讀取不到了。因此我們在過濾器的時候,已經將InputStream讀取過了一次,當來到Controller,SpringBoot讀取InputStream的時候自然是什么都讀取不到了

既然InputStream只能讀取一次,那我們可以把InputStream給保存下來,然后完整的傳下去SpringBoot就可以讀取到了,這里就需要用到HttpServletRequest的包裝類HttpServletRequestWrapper了,該類可以自定義一些方法
public class RequestWrapper extends HttpServletRequestWrapper {
private final byte[] body;
public RequestWrapper(HttpServletRequest request) throws IOException {
super(request);
//保存一份InputStream,將其轉換為字節數組
body = StreamUtils.copyToByteArray(request.getInputStream());
}
//轉換成String
public String getBodyString(){
return new String(body,StandardCharsets.UTF_8);
}
@Override
public BufferedReader getReader() throws IOException {
return new BufferedReader(new InputStreamReader(getInputStream()));
}
//把保存好的InputStream,傳下去
@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) {
}
};
}
}通過保存一份流,就可實現在過濾器中能拿到JSON參數,同時Controller也不會丟失參數

在過濾器放行的時候,放行的是包裝類和而不是原來的Request

以上是“SpringBoot過濾器中怎么獲取POST請求的JSON參數”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。