中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

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

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Spring Cloud Gateway 之 Filter

發布時間:2020-06-26 18:45:03 來源:網絡 閱讀:463 作者:程序員果果 欄目:編程語言

簡介

網關經常需要對路由請求進行過濾,進行一些操作,如鑒權之后構造頭部之類的,過濾的種類很多,如增加請求頭、增加請求 參數 、增加響應頭和斷路器等等功能,這就用到了Spring Cloud Gateway 的 Filter。

作用

當我們有很多個服務時,比如下圖中的user-service、goods-service、sales-service等服務,客戶端請求各個服務的Api時,每個服務都需要做相同的事情,比如鑒權、限流、日志輸出等。

Spring Cloud Gateway 之 Filter

對于這樣重復的工作,可以在微服務的上一層加一個全局的權限控制、限流、日志輸出的Api Gateway服務,然后再將請求轉發到具體的業務服務層。這個Api Gateway服務就是起到一個服務邊界的作用,外接的請求訪問系統,必須先通過網關層。

Spring Cloud Gateway 之 Filter

生命周期

Spring Cloud Gateway 的 Filter 的生命周期不像 Zuul 的那么豐富,它只有兩個:“pre” 和 “post”。

  • PRE: 這種過濾器在請求被路由之前調用。我們可利用這種過濾器實現身份驗證、在集群中選擇請求的微服務、記錄調試信息等。
  • POST:這種過濾器在路由到微服務以后執行。這種過濾器可用來為響應添加標準的 HTTP Header、收集統計信息和指標、將響應從微服務發送給客戶端等。

Spring Cloud Gateway 之 Filter

分類

Spring Cloud Gateway 的 Filter 從作用范圍可分為另外兩種GatewayFilter 與 GlobalFilter。

  • GatewayFilter:應用到單個路由或者一個分組的路由上。
  • GlobalFilter:應用到所有的路由上。

Gateway filter

過濾器允許以某種方式修改傳入的HTTP請求或傳出的HTTP響應。過濾器的作用域為特定路由。Spring Cloud Gateway包含許多內置的GatewayFilter工廠。

Spring Cloud Gateway 之 Filter

官方文檔都給出了這些過濾器工廠詳細的使用案例,在這里我們講解2個來演示下使用。

AddRequestHeader GatewayFilter Factory

application.yml如下:

spring:
  cloud:
    gateway:
      routes:
      - id: add_request_header_route
        uri: http://httpbin.org:80/get
        filters:
        - AddRequestHeader=X-Request-Foo, Bar
        predicates:
        - Method=GET

過濾器工廠會在匹配的請求頭加上一對請求頭,名稱為X-Request-Foo,值為Bar。

###RewritePath GatewayFilter Factory
在Nginx服務啟中有一個非常強大的功能就是重寫路徑,Spring Cloud Gateway默認也提供了這樣的功能,這個功能是Zuul沒有。

application.yml如下:

spring:
  cloud:
    gateway:
      routes:
      - id: rewritepath_route
        uri: http://httpbin.org
        predicates:
        - Path=/foo/**
        filters:
        - RewritePath=/foo/(?<segment>.*), /$\{segment}

所有的/foo/**開始的路徑都會命中配置的router。
請求http://httpbin.org/foo/get ,會轉到http://httpbin.org/get,結果如下:

{
  "args": {

  },
  "headers": {
    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8",
    "Accept-Encoding": "gzip, deflate, br",
    "Accept-Language": "zh-CN,zh;q=0.9,zh-TW;q=0.8",
    "Cache-Control": "max-age=0",
    "Cookie": "Hm_lvt_0c0e9d9b1e7d617b3e6842e85b9fb068=1550127915; sensorsdata2015jssdkcross=%7B%22distinct_id%22%3A%22168eada0ded53b-0d5d8c3ba9b7a2-10316653-1296000-168eada0dee3ad%22%2C%22%24device_id%22%3A%22168eada0ded53b-0d5d8c3ba9b7a2-10316653-1296000-168eada0dee3ad%22%2C%22props%22%3A%7B%7D%7D; _gauges_unique_month=1; _gauges_unique_year=1; _gauges_unique=1",
    "Forwarded": "proto=http;host=\"127.0.0.1:8080\";for=\"127.0.0.1:62278\"",
    "Host": "httpbin.org",
    "Upgrade-Insecure-Requests": "1",
    "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36",
    "X-Forwarded-Host": "127.0.0.1:8080",
    "X-Forwarded-Prefix": "/foo"
  },
  "origin": "127.0.0.1, 124.74.78.150, 127.0.0.1",
  "url": "https://127.0.0.1:8080/get"
}

自定義GatewayFilter

Spring Cloud Gateway內置了的過濾器工廠,足夠是大部分場景使用,而且我們可以實現GatewayFilter和Ordered 這兩個接口來自定義過濾器。代碼如下:

/**
 * 統計某個或者某種路由的處理時長
 */
public class CustomerGatewayFilter implements GatewayFilter, Ordered {

    private static final Logger log = LoggerFactory.getLogger( CustomerGatewayFilter.class );
    private static final String COUNT_START_TIME = "countStartTime";

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        exchange.getAttributes().put(COUNT_START_TIME, Instant.now().toEpochMilli() );
        return chain.filter(exchange).then(
                Mono.fromRunnable(() -> {
                    long startTime = exchange.getAttribute(COUNT_START_TIME);
                    long endTime=(Instant.now().toEpochMilli() - startTime);
                    log.info(exchange.getRequest().getURI().getRawPath() + ": " + endTime + "ms");
                })
        );
    }

    @Override
    public int getOrder() {
        return 0;
    }
}

上述代碼中,getOrder()方法是來給過濾器設定優先級別的,值越大則優先級越低。需要將自定義的GatewayFilter 注冊到router中,代碼如下:

@Bean
public RouteLocator customerRouteLocator(RouteLocatorBuilder builder) {
    return builder.routes()
            .route(r -> r.path("/customer/**")
                    .filters(f -> f.filter(new CustomerGatewayFilter())
                            .addResponseHeader("X-Response-test", "test"))
                    .uri("http://httpbin.org:80/get")
                    .id("customer_filter_router")
            )
            .build();
}

使用 curl 測試,命令行輸入:

curl http://localhost:8080/customer/555

控制臺輸出如下:

2019-02-22 10:39:47.840  INFO 1310 --- [ctor-http-nio-3] com.gf.config.CustomerGatewayFilter      : /customer/555: 314ms

自定義過濾器工廠

自定義GatewayFilter又有兩種實現方式,一種是上面的直接 實現GatewayFilter接口,另一種是 自定義過濾器工廠(繼承AbstractGatewayFilterFactory類) , 選擇自定義過濾器工廠的方式,可以在配置文件中配置過濾器了。

@Component
public class CustomerGatewayFilterFactory extends AbstractGatewayFilterFactory<CustomerGatewayFilterFactory.Config> {

    private static final Logger log = LoggerFactory.getLogger( CustomerGatewayFilterFactory.class );
    private static final String COUNT_START_TIME = "countStartTime";

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

    public CustomerGatewayFilterFactory() {
        super(Config.class);
        log.info("Loaded GatewayFilterFactory [CustomerGatewayFilterFactory]");
    }

    @Override
    public GatewayFilter apply(Config config) {
        return (exchange, chain) -> {
            if (!config.isEnabled()) {
                return chain.filter(exchange);
            }
            exchange.getAttributes().put(COUNT_START_TIME, System.currentTimeMillis());
            return chain.filter(exchange).then(
                    Mono.fromRunnable(() -> {
                        Long startTime = exchange.getAttribute(COUNT_START_TIME);
                        if (startTime != null) {
                            StringBuilder sb = new StringBuilder(exchange.getRequest().getURI().getRawPath())
                                    .append(": ")
                                    .append(System.currentTimeMillis() - startTime)
                                    .append("ms");
                            sb.append(" params:").append(exchange.getRequest().getQueryParams());
                            log.info(sb.toString());
                        }
                    })
            );
        };
    }

    public static class Config {
        /**
         * 控制是否開啟統計
         */
        private boolean enabled;

        public Config() {}

        public boolean isEnabled() {
            return enabled;
        }

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

}

application.yml 中 網關路由配置如下:

spring:
  profiles: elapse_route
  cloud:
    gateway:
      routes:
        - id: elapse_route
          uri: http://httpbin.org:80/get
          filters:
          - Customer=true
          predicates:
          - Method=GET

使用 curl 測試,命令行輸入:

curl http://localhost:8080/customer?foo=1

控制臺輸出如下:

2019-02-23 13:37:08.769  INFO 1700 --- [ctor-http-nio-3] c.g.config.CustomerGatewayFilterFactory  : /customer: 585ms params:{foo=[1]}

Global filter

Spring Cloud Gateway框架內置的GlobalFilter如下:

Spring Cloud Gateway 之 Filter

內置的 GlobalFilter 能夠滿足大多數的需求了,但是如果遇到特殊情況,內置滿足不了我們的需求,還可以自定義GlobalFilter。

自定義GlobalFilter

下面的我們自定義一個GlobalFilter,去校驗所有請求的請求參數中是否包含“token”,如何不包含請求參數“token”則不轉發路由,否則執行正常的邏輯。

/**
 * Token 校驗全局過濾器
 */
@Component
public class AuthorizeFilter implements GlobalFilter, Ordered {

    private static final Logger log = LoggerFactory.getLogger( AuthorizeFilter.class );

    private static final String AUTHORIZE_TOKEN = "token";

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String token = exchange.getRequest().getQueryParams().getFirst( AUTHORIZE_TOKEN );
        if ( StringUtils.isBlank( token )) {
            log.info( "token is empty ..." );
            exchange.getResponse().setStatusCode( HttpStatus.UNAUTHORIZED );
            return exchange.getResponse().setComplete();
        }
        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        return 0;
    }

}

使用 curl 測試,命令行輸入:

curl http://localhost:8080/customer?foo=1

控制臺輸出如下:

token is empty ...

源碼 : https://github.com/gf-huanchupk/SpringCloudLearning/tree/master/chapter13/springcloud-gateway-filter

歡迎關注我的公眾號《程序員果果》,關注有驚喜~~
Spring Cloud Gateway 之 Filter

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

章丘市| 平乐县| 天长市| 西峡县| 禹州市| 灌云县| 琼结县| 罗源县| 边坝县| 宿迁市| 上林县| 陕西省| 新巴尔虎右旗| 子长县| 津南区| 桂阳县| 漯河市| 湘乡市| 沾化县| 榆树市| 崇礼县| 汉阴县| 新蔡县| 二连浩特市| 嵊泗县| 志丹县| 宜昌市| 伊宁市| 江西省| 尼勒克县| 蓬安县| 乾安县| 项城市| 乌鲁木齐县| 铜陵市| 台东市| 获嘉县| 韶山市| 仁怀市| 夏河县| 喀喇沁旗|