欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

SpringBoot攔截器如何獲取http請求參數(shù)

 更新時(shí)間:2020年09月10日 09:20:18   作者:上帝愛吃蘋果-Soochow  
這篇文章主要給大家介紹了SpringBoot攔截器如何獲取http請求參數(shù)的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

1.1、獲取http請求參數(shù)是一種剛需

我想有的小伙伴肯定有過獲取http請求的需要,比如想

  1. 前置獲取參數(shù),統(tǒng)計(jì)請求數(shù)據(jù)
  2. 做服務(wù)的接口簽名校驗(yàn)
  3. 敏感接口監(jiān)控日志
  4. 敏感接口防重復(fù)提交

等等各式各樣的場景,這時(shí)你就需要獲取 HTTP 請求的參數(shù)或者請求body,一般思路有兩種,一種就是自定義個(gè)AOP去攔截目標(biāo)方法,第二種就是使用攔截器。整體比較來說,使用攔截器更靈活些,因?yàn)槊總€(gè)接口的請求參數(shù)定義不同,使用AOP很難細(xì)粒度的獲取到變量參數(shù),本文主線是采用攔截器來獲取HTTP請求。

1.2、定義攔截器獲取請求

基于 spring-boot-starter-parent 2.1.9.RELEASE

看起來這個(gè)很簡單,這里就直接上code,定義個(gè)攔截器

/**
 * @author axin
 * @summary HTTP請求攔截器
 */
@Slf4j
public class RequestInterceptor implements HandlerInterceptor {

  @Override
  public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

    //獲取請求參數(shù)
    String queryString = request.getQueryString();
    log.info("請求參數(shù):{}", queryString);

    //獲取請求body
    byte[] bodyBytes = StreamUtils.copyToByteArray(request.getInputStream());
    String body = new String(bodyBytes, request.getCharacterEncoding());

    log.info("請求體:{}", body);
    return true;
  }
}

然后把這個(gè)攔截器配置一下中:

/**
 * WebMVC配置,你可以集中在這里配置攔截器、過濾器、靜態(tài)資源緩存等
 */
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

  @Override
  public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(new RequestInterceptor()).addPathPatterns("/**");
  }
}

定義個(gè)接口測試一下

/**
 * @author axin
 * @summary 提交測試接口
 */
@Slf4j
@RestController
public class MyHTTPController {

  @GetMapping("/v1/get")
  public void get(@RequestParam("one") String one,
          @RequestParam("two") BigDecimal number) {
    log.info("參數(shù):{},{}", one, number);
  }


  @PostMapping("/v1/post")
  public void check(@RequestBody User user) {

    log.info("{}", JSON.toJSONString(user));
  }
}

GET請求獲取請求參數(shù)示例:

POST請求獲取請求Body示例:

我們發(fā)現(xiàn)攔截器在獲取HTTP請求的body時(shí)出現(xiàn)了 400 (Required request body is missing: public void com.axin.world.controller.MyHTTPController.check(com.axin.world.domain.User));同時(shí)也發(fā)現(xiàn)攔截器竟然走了兩遍,這又是咋回事呢?

1.3、為什么攔截器會重復(fù)調(diào)兩遍呢?

其實(shí)是因?yàn)?tomcat截取到異常后就轉(zhuǎn)發(fā)到/error頁面,就在這個(gè)轉(zhuǎn)發(fā)的過程中導(dǎo)致了springmvc重新開始DispatcherServlet的整個(gè)流程,所以攔截器執(zhí)行了兩次,我們可以看下第二次調(diào)用時(shí)的url路徑:

1.4、ServletInputStream(CoyoteInputStream) 輸入流無法重復(fù)調(diào)用

而之前出現(xiàn)的 Required request body is missing 錯(cuò)誤 其實(shí)是ServletInputStream被讀取后無法第二次再讀取了,所以我們要把讀取過的內(nèi)容存下來,然后需要的時(shí)候?qū)ν馓峁┛杀恢貜?fù)讀取的ByteArrayInputStream。

對于MVC的過濾器來說,我們就需要重寫 ServletInputStream 的 getInputStream()方法。

1.5、自定義 HttpServletRequestWrapper

為了 重寫 ServletInputStream 的 getInputStream()方法,我們需要自定義一個(gè) HttpServletRequestWrapper :

/**
* @author Axin
* @summary 自定義 HttpServletRequestWrapper 來包裝輸入流
*/
public class AxinHttpServletRequestWrapper extends HttpServletRequestWrapper {

  /**
   * 緩存下來的HTTP body
   */
  private byte[] body;

  public AxinHttpServletRequestWrapper(HttpServletRequest request) throws IOException {
    super(request);
    body = StreamUtils.copyToByteArray(request.getInputStream());
  }

  /**
   * 重新包裝輸入流
   * @return
   * @throws IOException
   */
  @Override
  public ServletInputStream getInputStream() throws IOException {
    InputStream bodyStream = new ByteArrayInputStream(body);
    return new ServletInputStream() {

      @Override
      public int read() throws IOException {
        return bodyStream.read();
      }

      /**
       * 下面的方法一般情況下不會被使用,如果你引入了一些需要使用ServletInputStream的外部組件,可以重點(diǎn)關(guān)注一下。
       * @return
       */
      @Override
      public boolean isFinished() {
        return false;
      }

      @Override
      public boolean isReady() {
        return true;
      }

      @Override
      public void setReadListener(ReadListener readListener) {

      }
    };
  }
  
  @Override
  public BufferedReader getReader() throws IOException {
    InputStream bodyStream = new ByteArrayInputStream(body);
    return new BufferedReader(new InputStreamReader(getInputStream()));
  }
}

然后定義一個(gè) DispatcherServlet子類來分派 上面自定義的 AxinHttpServletRequestWrapper :

/**
* @author Axin
* @summary 自定義 DispatcherServlet 來分派 AxinHttpServletRequestWrapper
*/
public class AxinDispatcherServlet extends DispatcherServlet {

  /**
   * 包裝成我們自定義的request
   * @param request
   * @param response
   * @throws Exception
   */
  @Override
  protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
    super.doDispatch(new AxinHttpServletRequestWrapper(request), response);
  }
}

然后配置一下:

/**
 * WebMVC配置,你可以集中在這里配置攔截器、過濾器、靜態(tài)資源緩存等
 */
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

  @Override
  public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(new RequestInterceptor()).addPathPatterns("/**");
  }

  @Bean
  @Qualifier(DispatcherServletAutoConfiguration.DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
  public DispatcherServlet dispatcherServlet() {
    return new AxinDispatcherServlet();
  }
}

再調(diào)用一下 POST請求:

請求成功!

1.5、總結(jié)一下 展望一下

如果你想對HTTP請求做些騷操作,那么前置獲取HTTP請求參數(shù)是前提,為此文本給出了使用MVC攔截器獲取參數(shù)的樣例。

在獲取HTTP Body 的時(shí)候,出現(xiàn)了 Required request body is missing 的錯(cuò)誤,同時(shí)攔截器還出現(xiàn)執(zhí)行了兩遍的問題,這是因?yàn)?ServletInputStream被讀取了兩遍導(dǎo)致的,tomcat截取到異常后就轉(zhuǎn)發(fā)到 /error 頁面 被攔截器攔截到了,攔截器也就執(zhí)行了兩遍。

為此我們通過自定義 HttpServletRequestWrapper 來包裝一個(gè)可被重讀讀取的輸入流,來達(dá)到期望的攔截效果。

在獲取到HTTP的請求參數(shù)后,我們可以前置做很多操作,比如常用的服務(wù)端接口簽名驗(yàn)證,敏感接口防重復(fù)請求等等。

個(gè)人水平有限,如果文章有邏輯錯(cuò)誤或表述問題還請指出,歡迎一起交流。

到此這篇關(guān)于SpringBoot攔截器如何獲取http請求參數(shù)的文章就介紹到這了,更多相關(guān)SpringBoot攔截器獲取http請求參數(shù)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 基于Java實(shí)現(xiàn)雙向鏈表

    基于Java實(shí)現(xiàn)雙向鏈表

    這篇文章主要為大家詳細(xì)介紹了基于Java實(shí)現(xiàn)雙向鏈表,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-05-05
  • 關(guān)于Java大整數(shù)運(yùn)算之BigInteger類

    關(guān)于Java大整數(shù)運(yùn)算之BigInteger類

    這篇文章主要介紹了關(guān)于Java大整數(shù)運(yùn)算之BigInteger類,BigInteger提供高精度整型數(shù)據(jù)類型及相關(guān)操作,所有操作中,都以二進(jìn)制補(bǔ)碼形式表示,需要的朋友可以參考下
    2023-05-05
  • 解決cmd執(zhí)行javac報(bào)錯(cuò):不是內(nèi)部或外部命令,也不是可運(yùn)行的程序

    解決cmd執(zhí)行javac報(bào)錯(cuò):不是內(nèi)部或外部命令,也不是可運(yùn)行的程序

    剛接觸JAVA的新手可能就不知道怎么解決'JAVAC'不是內(nèi)部命令或外部命令,這篇文章主要給大家介紹了關(guān)于解決cmd執(zhí)行javac報(bào)錯(cuò):不是內(nèi)部或外部命令,也不是可運(yùn)行的程序的相關(guān)資料,需要的朋友可以參考下
    2023-11-11
  • Spring解決依賴版本不一致報(bào)錯(cuò)問題

    Spring解決依賴版本不一致報(bào)錯(cuò)問題

    許多同學(xué)經(jīng)常會遇到依賴版本不一致導(dǎo)致代碼報(bào)錯(cuò),所以這篇文章就給大家詳細(xì)介紹一下Spring解決依賴版本不一致報(bào)錯(cuò)問題,需要的朋友跟著小編一起來看看吧
    2023-07-07
  • SpringBoot接口返回結(jié)果封裝方法實(shí)例詳解

    SpringBoot接口返回結(jié)果封裝方法實(shí)例詳解

    在實(shí)際項(xiàng)目中,一般會把結(jié)果放在一個(gè)封裝類中,封裝類中包含http狀態(tài)值,狀態(tài)消息,以及實(shí)際的數(shù)據(jù)。這里主要記錄兩種方式,通過實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友參考下吧
    2021-09-09
  • Java?BOI與NIO超詳細(xì)實(shí)例精講

    Java?BOI與NIO超詳細(xì)實(shí)例精講

    在Java的軟件設(shè)計(jì)開發(fā)中,通信架構(gòu)是不可避免的,我們在進(jìn)行不同系統(tǒng)或者不同進(jìn)程之間的數(shù)據(jù)交互,或者在高并發(fā)下的通信場景下都需要用到網(wǎng)絡(luò)通信相關(guān)的技術(shù),對于一些經(jīng)驗(yàn)豐富的程序員來說,Java早期的網(wǎng)絡(luò)通信架構(gòu)存在一些缺陷,這篇文章介紹Java?BOI與NIO
    2022-11-11
  • SpringMVC中@RequestMapping注解的實(shí)現(xiàn)

    SpringMVC中@RequestMapping注解的實(shí)現(xiàn)

    RequestMapping是一個(gè)用來處理請求地址映射的注解,本文主要介紹了SpringMVC中@RequestMapping注解的實(shí)現(xiàn),具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-01-01
  • Spark調(diào)度架構(gòu)原理詳解

    Spark調(diào)度架構(gòu)原理詳解

    這篇文章主要介紹了Spark 調(diào)度架構(gòu)原理詳解,具有一定借鑒價(jià)值,需要的朋友可以參考下。
    2017-12-12
  • 解釋:int型默認(rèn)值為0的問題

    解釋:int型默認(rèn)值為0的問題

    這篇文章主要介紹了解釋:int型默認(rèn)值為0的問題,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-08-08
  • spring整合shiro框架的實(shí)現(xiàn)步驟記錄

    spring整合shiro框架的實(shí)現(xiàn)步驟記錄

    Shiro是一個(gè)強(qiáng)大易用的Java安全框架,提供了認(rèn)證、授權(quán)、加密和會話管理等功能。下面這篇文章主要給大家介紹了關(guān)于spring整合shiro框架的實(shí)現(xiàn)步驟,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2018-05-05

最新評論