溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

SpringBoot過(guò)濾器中怎么獲取POST請(qǐng)求的JSON參數(shù)

發(fā)布時(shí)間:2021-08-30 09:24:11 來(lái)源:億速云 閱讀:331 作者:小新 欄目:開(kāi)發(fā)技術(shù)

這篇文章主要為大家展示了“SpringBoot過(guò)濾器中怎么獲取POST請(qǐng)求的JSON參數(shù)”,內(nèi)容簡(jiǎn)而易懂,條理清晰,希望能夠幫助大家解決疑惑,下面讓小編帶領(lǐng)大家一起研究并學(xué)習(xí)一下“SpringBoot過(guò)濾器中怎么獲取POST請(qǐng)求的JSON參數(shù)”這篇文章吧。

SpringBoot過(guò)濾器獲取POST請(qǐng)求的JSON參數(shù)

項(xiàng)目中需要將每個(gè)請(qǐng)求的路徑和請(qǐng)求參數(shù)以及響應(yīng)結(jié)果,都記錄在日志中,這樣在出現(xiàn)問(wèn)題時(shí)可以快速定位是哪里出現(xiàn)了問(wèn)題。

想到了使用過(guò)濾器來(lái)實(shí)現(xiàn)這個(gè)功能

當(dāng)請(qǐng)求來(lái)到過(guò)濾器時(shí),會(huì)有一個(gè)Request參數(shù),通過(guò)該參數(shù)就能獲取到請(qǐng)求路徑和請(qǐng)求參數(shù),以及相關(guān)內(nèi)容

parameterMap = httpRequest.getParameterMap();
String requestMethod = httpRequest.getMethod();
String remoteAddr = httpRequest.getRemoteAddr();
int remotePort = httpRequest.getRemotePort();

上面的getParameterMap(),只能夠獲取到GET請(qǐng)求的參數(shù),如果是POST方法傳的JSON那就沒(méi)法獲取到,那如何獲取呢,POST的請(qǐng)求是在請(qǐng)求體body中,而POST請(qǐng)求中的body參數(shù)是已流形式存在的

所以我們可以通過(guò)獲取到輸入流來(lái)獲取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());

通過(guò)上面的方法,我們確實(shí)能在過(guò)濾器中獲取到POST的JSON參數(shù)了,但是按照上面的方法實(shí)現(xiàn)的過(guò)濾器,我們會(huì)發(fā)現(xiàn),當(dāng)請(qǐng)求經(jīng)過(guò)過(guò)濾器來(lái)到Controller的時(shí)候,請(qǐng)求參數(shù)不見(jiàn)了

SpringBoot過(guò)濾器中怎么獲取POST請(qǐng)求的JSON參數(shù)

可以看到,過(guò)濾器確實(shí)拿到JSON參數(shù),但是接著報(bào)了一個(gè)request body missing的異常,也就是請(qǐng)求來(lái)到Controller時(shí),參數(shù)沒(méi)有了,這是為啥呢?我們先去源碼看看,Controller平時(shí)是怎么拿到請(qǐng)求參數(shù)的吧

SpringBoot過(guò)濾器中怎么獲取POST請(qǐng)求的JSON參數(shù)

根據(jù)DeBug,可以看到SpringBoot處理請(qǐng)求的最主要的兩個(gè)方法是上圖紅框的doServicedoDisparch方法,上面就是通過(guò)反射去獲取參數(shù)名去匹配等

SpringBoot過(guò)濾器中怎么獲取POST請(qǐng)求的JSON參數(shù)

來(lái)到invokeForRequest方法,這里面的getMethodArgumentValues,就是SpringBoot獲取請(qǐng)求參數(shù)的入口,進(jìn)入入口后

SpringBoot過(guò)濾器中怎么獲取POST請(qǐng)求的JSON參數(shù)

再經(jīng)過(guò)上面的紅框,就能看到SpringBoot獲取POST請(qǐng)求JSON的參數(shù)的真面目了

SpringBoot過(guò)濾器中怎么獲取POST請(qǐng)求的JSON參數(shù)

從源碼我們可以看到

SpringBoot也是通過(guò)獲取request的輸入流來(lái)獲取參數(shù),這樣上面的疑問(wèn)就能解開(kāi)了,為什么經(jīng)過(guò)過(guò)濾器來(lái)到Controller請(qǐng)求參數(shù)就沒(méi)了,這是因?yàn)?InputStream read方法內(nèi)部有一個(gè),postion,標(biāo)志當(dāng)前流讀取到的位置,每讀取一次,位置就會(huì)移動(dòng)一次,如果讀到最后,InputStream.read方法會(huì)返回-1,標(biāo)志已經(jīng)讀取完了,如果想再次讀取,可以調(diào)用inputstream.reset方法,position就會(huì)移動(dòng)到上次調(diào)用mark的位置,mark默認(rèn)是0,所以就能從頭再讀了。但是呢 是否能reset又是由markSupported決定的,為true能reset,為false就不能reset,從源碼可以看到,markSupported是為false的,而且一調(diào)用reset就是直接異常

SpringBoot過(guò)濾器中怎么獲取POST請(qǐng)求的JSON參數(shù)

所以這也就代表,InputStream只能被讀取一次,后面就讀取不到了。因此我們?cè)谶^(guò)濾器的時(shí)候,已經(jīng)將InputStream讀取過(guò)了一次,當(dāng)來(lái)到Controller,SpringBoot讀取InputStream的時(shí)候自然是什么都讀取不到了

SpringBoot過(guò)濾器中怎么獲取POST請(qǐng)求的JSON參數(shù)

既然InputStream只能讀取一次,那我們可以把InputStream給保存下來(lái),然后完整的傳下去SpringBoot就可以讀取到了,這里就需要用到HttpServletRequest的包裝類HttpServletRequestWrapper了,該類可以自定義一些方法

我們創(chuàng)建一個(gè)類并繼承這個(gè)包裝類

public class RequestWrapper extends HttpServletRequestWrapper {
    private final byte[] body;
    public RequestWrapper(HttpServletRequest request) throws IOException {
        super(request);
        //保存一份InputStream,將其轉(zhuǎn)換為字節(jié)數(shù)組
        body = StreamUtils.copyToByteArray(request.getInputStream());
    }
	//轉(zhuǎn)換成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) {
            }
        };
    }
}

通過(guò)保存一份流,就可實(shí)現(xiàn)在過(guò)濾器中能拿到JSON參數(shù),同時(shí)Controller也不會(huì)丟失參數(shù)

SpringBoot過(guò)濾器中怎么獲取POST請(qǐng)求的JSON參數(shù)

有一點(diǎn)需要注意的

在過(guò)濾器放行的時(shí)候,放行的是包裝類和而不是原來(lái)的Request

SpringBoot過(guò)濾器中怎么獲取POST請(qǐng)求的JSON參數(shù)

以上是“SpringBoot過(guò)濾器中怎么獲取POST請(qǐng)求的JSON參數(shù)”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對(duì)大家有所幫助,如果還想學(xué)習(xí)更多知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI