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

SpringCloud Gateway自定義filter獲取body中的數據為空的問題

 更新時間:2020年10月31日 13:34:18   作者:mameng1998  
這篇文章主要介紹了SpringCloud Gateway自定義filter獲取body中的數據為空,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下

最近在使用SpringCloud Gateway進行網關的開發(fā),我使用的版本是:SpringBoot的2.3.4.RELEASE+SpringCloud的Hoxton.SR8,在自定義過濾器時需要獲取ServerHttpRequest中body的數據,發(fā)現一直無法獲取到數據,經過各種百度、谷歌,再加上自己的實踐,終于找到解決方案:
1、首先創(chuàng)建一個全局過濾器把body中的數據緩存起來

package com.cloudpath.gateway.portal.filter;

import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

/**
 * @author mazhen
 * @className CacheBodyGlobalFilter
 * @Description 把body中的數據緩存起來
 * @date 2020/10/28 18:02
 */
@Slf4j
@Component
public class CacheBodyGlobalFilter implements Ordered, GlobalFilter {

  // public static final String CACHE_REQUEST_BODY_OBJECT_KEY = "cachedRequestBodyObject";

  @Override
  public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
    if (exchange.getRequest().getHeaders().getContentType() == null) {
      return chain.filter(exchange);
    } else {
      return DataBufferUtils.join(exchange.getRequest().getBody())
          .flatMap(dataBuffer -> {
            DataBufferUtils.retain(dataBuffer);
            Flux<DataBuffer> cachedFlux = Flux
                .defer(() -> Flux.just(dataBuffer.slice(0, dataBuffer.readableByteCount())));
            ServerHttpRequest mutatedRequest = new ServerHttpRequestDecorator(
                exchange.getRequest()) {
              @Override
              public Flux<DataBuffer> getBody() {
                return cachedFlux;
              }
            };
            //exchange.getAttributes().put(CACHE_REQUEST_BODY_OBJECT_KEY, cachedFlux);

            return chain.filter(exchange.mutate().request(mutatedRequest).build());
          });
    }
  }

  @Override
  public int getOrder() {
    return Ordered.HIGHEST_PRECEDENCE;
  }

}

CacheBodyGlobalFilter這個全局過濾器的目的就是把原有的request請求中的body內容讀出來,并且使用ServerHttpRequestDecorator這個請求裝飾器對request進行包裝,重寫getBody方法,并把包裝后的請求放到過濾器鏈中傳遞下去。這樣后面的過濾器中再使用exchange.getRequest().getBody()來獲取body時,實際上就是調用的重載后的getBody方法,獲取的最先已經緩存了的body數據。這樣就能夠實現body的多次讀取了。
值得一提的是,這個過濾器的order設置的是Ordered.HIGHEST_PRECEDENCE,即最高優(yōu)先級的過濾器。優(yōu)先級設置這么高的原因是某些系統(tǒng)內置的過濾器可能也會去讀body,這樣就會導致我們自定義過濾器中獲取body的時候報body只能讀取一次這樣的錯誤如下:

java.lang.IllegalStateException: Only one connection receive subscriber allowed.
	at reactor.ipc.netty.channel.FluxReceive.startReceiver(FluxReceive.java:279)
	at reactor.ipc.netty.channel.FluxReceive.lambda$subscribe$2(FluxReceive.java:129)
	at 

所以,必須把CacheBodyGlobalFilter的優(yōu)先級設到最高。
2、在自定義的過濾器中嘗試獲取body中的數據

package com.cloudpath.iam.gateway.customerfilter;

import com.cloudpath.iam.gateway.utils.FilterRequestResponseUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Flux;

import java.util.Arrays;
import java.util.List;

/**
 * @author by mazhen
 * @Classname TestGatewayFilterFactory
 * @Description 自定義過濾器獲取body中的數據
 * @Date 2020/10/27 14:38
 */
@Component
@Slf4j
public class TestGatewayFilterFactory extends AbstractGatewayFilterFactory<TestGatewayFilterFactory.Config> {


  @Override
  public List<String> shortcutFieldOrder() {
    return Arrays.asList("enabled");
  }

  public TestGatewayFilterFactory() {
    super(Config.class);
    log.info("Loaded TestGatewayFilterFactory");
  }

  @Override
  public GatewayFilter apply(Config config) {
    return (exchange, chain) -> {
      if (!config.isEnabled()) {
        return chain.filter(exchange);
      }

      if (null != exchange) {
        ServerHttpRequest httpRequest = exchange.getRequest();
          try {

            Flux<DataBuffer> dataBufferFlux = httpRequest.getBody();
            //獲取body中的數據
            String body = FilterRequestResponseUtil.resolveBodyFromRequest(dataBufferFlux);
            log.info("body:{}",body);

          } catch (Exception e) {
            log.error("異常:",e);
            return chain.filter(exchange);
          }
      }
      return chain.filter(exchange);
    };
  }


  public static class Config {
    /**
     * 控制是否開啟統(tǒng)計
     */
    private boolean enabled;

    public Config() {
    }

    public boolean isEnabled() {
      return enabled;
    }

    public void setEnabled(boolean enabled) {
      this.enabled = enabled;
    }
  }
}

3、解析body的工具類

package com.cloudpath.iam.gateway.utils;


import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferUtils;
import reactor.core.publisher.Flux;
import java.nio.CharBuffer;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.atomic.AtomicReference;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author mazhen
 * @className FilterHeadersUtil
 * @Description 過濾器請求/響應工具類
 * @date 2020/10/29 9:31
 */
public final class FilterRequestResponseUtil {

  /**
   * spring cloud gateway 獲取post請求的body體
   * @param body
   * @return
   */
  public static String resolveBodyFromRequest( Flux<DataBuffer> body){
    AtomicReference<String> bodyRef = new AtomicReference<>();
    // 緩存讀取的request body信息
    body.subscribe(dataBuffer -> {
      CharBuffer charBuffer = StandardCharsets.UTF_8.decode(dataBuffer.asByteBuffer());
      DataBufferUtils.release(dataBuffer);
      bodyRef.set(charBuffer.toString());
    });
    //獲取request body
    return bodyRef.get();

  }

  /**
   * 讀取body內容
   * @param body
   * @return
   */
  public static String resolveBodyFromRequest2( Flux<DataBuffer> body){
    StringBuilder sb = new StringBuilder();

    body.subscribe(buffer -> {
      byte[] bytes = new byte[buffer.readableByteCount()];
      buffer.read(bytes);
      DataBufferUtils.release(buffer);
      String bodyString = new String(bytes, StandardCharsets.UTF_8);
      sb.append(bodyString);
    });
    return formatStr(sb.toString());
  }

  /**
   * 去掉空格,換行和制表符
   * @param str
   * @return
   */
  private static String formatStr(String str){
    if (str != null && str.length() > 0) {
      Pattern p = Pattern.compile("\\s*|\t|\r|\n");
      Matcher m = p.matcher(str);
      return m.replaceAll("");
    }
    return str;
  }
}

解析body的內容,網上普遍是上面的兩種方式,親測resolveBodyFromRequest方法解析body中的數據,沒有1024字節(jié)的限制。
ps:我傳的參數有1萬多字節(jié)。。。。。。。
大家可以按需所選。

到此這篇關于SpringCloud Gateway自定義filter獲取body中的數據為空的文章就介紹到這了,更多相關SpringCloud Gateway自定義filter內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • java編程兩種樹形菜單結構的轉換代碼

    java編程兩種樹形菜單結構的轉換代碼

    這篇文章主要介紹了java編程兩種樹形菜單結構的轉換代碼,首先介紹了兩種樹形菜單結構的代碼,然后展示了轉換器實例代碼,最后分享了相關實例及結果演示,具有一定借鑒價值,需要的朋友可以了解下。
    2017-12-12
  • SpringBoot自定義HttpMessageConverter操作

    SpringBoot自定義HttpMessageConverter操作

    這篇文章主要介紹了SpringBoot自定義HttpMessageConverter的操作,具有很好的參考價值,如有錯誤或未考慮完全的地方,望不吝賜教
    2021-08-08
  • Java重點梳理類與對象核心原理

    Java重點梳理類與對象核心原理

    類(class)和對象(object)是兩種以計算機為載體的計算機語言的合稱。對象是對客觀事物的抽象,類是對對象的抽象。類是一種抽象的數據類型
    2022-07-07
  • spring boot 部署為jar包的方法示例

    spring boot 部署為jar包的方法示例

    本篇文章主要介紹了spring boot 部署為jar的方法示例,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-10-10
  • 詳解Java的Hibernate框架中的搜索工具的運用

    詳解Java的Hibernate框架中的搜索工具的運用

    這篇文章主要介紹了詳解Java的Hibernate框架中的搜索工具的運用,Hibernate是Java的SSH三大web開發(fā)框架之一,需要的朋友可以參考下
    2015-11-11
  • 淺談從Java中的棧和堆,進而衍生到值傳遞

    淺談從Java中的棧和堆,進而衍生到值傳遞

    這篇文章主要介紹了淺談從Java中的棧和堆,進而衍生到值傳遞,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-09-09
  • SpringBoot jar包大小優(yōu)化問題及解決

    SpringBoot jar包大小優(yōu)化問題及解決

    這篇文章主要介紹了SpringBoot jar包大小優(yōu)化問題及解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-11-11
  • Java中synchronized的四種用法詳解

    Java中synchronized的四種用法詳解

    這篇文章主要介紹了Java中synchronized的四種用法詳解,當我們處理多線程處理同步問題的時候就會用到synchronized這個關鍵字,下面介紹下synchronized的四種用法,需要的朋友可以參考下
    2024-01-01
  • 基于CyclicBarrier和CountDownLatch的使用區(qū)別說明

    基于CyclicBarrier和CountDownLatch的使用區(qū)別說明

    這篇文章主要介紹了基于CyclicBarrier和CountDownLatch的使用區(qū)別說明,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-09-09
  • 詳解Spring3.x 升級至 Spring4.x的方法

    詳解Spring3.x 升級至 Spring4.x的方法

    本篇文章主要介紹了詳解Spring3.x 升級至 Spring4.x的方法,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-04-04

最新評論