Gateway網(wǎng)關(guān)過(guò)濾器

spirngcloud Gateway根據(jù)作用范圍劃分為 GatewayFilter 和 GlobalFilter,二者區(qū)別如下:
GatewayFilter:網(wǎng)關(guān)過(guò)濾器,需要通過(guò) spring.cloud.routes.filters 配置在具體路由下,只作用在當(dāng)前路由上或通過(guò)spirng.cloud.default-filters 配置在全局,作用在所有路由上。
GlobalFilter:全局過(guò)濾器,不需要在配置文件中配置,作用在所有的路由上,最終通過(guò) GatewayFilterAdapter 包裝成 GatewayFilterChain 可識(shí)別的過(guò)濾器,它為請(qǐng)求業(yè)務(wù)以及路由的 URI 轉(zhuǎn)換為真實(shí)業(yè)務(wù)服務(wù)請(qǐng)求地址的核心過(guò)濾器,不需要配置系統(tǒng)初始化時(shí)加載,并作用在每個(gè)路由上。

1. 網(wǎng)關(guān)過(guò)濾器GatewayFilter

網(wǎng)關(guān)過(guò)濾器用于攔截并鏈?zhǔn)教幚韜eb請(qǐng)求,可以實(shí)現(xiàn)橫切與應(yīng)用無(wú)關(guān)的需求,比如:安全、訪問(wèn)超時(shí)的設(shè)置等。修改傳入的HTTP請(qǐng)求或傳出HTTP響應(yīng)。Spring Cloud Gateway 包含許多內(nèi)置的網(wǎng)關(guān)過(guò)濾器工廠一共有22個(gè),包括頭部過(guò)濾器、路徑過(guò)濾器、Hystrix過(guò)濾器和重寫請(qǐng)求URL的過(guò)濾器,還有參數(shù)和狀態(tài)碼等其他類型的過(guò)濾器,根據(jù)過(guò)濾器工廠的用途來(lái)劃分,可以分為以下幾種:Header、Parameter、Path、Body、Status、Session、Redirect、Retry、RateLimiter和Hystrix。

1.1 path過(guò)濾器

Path 路徑過(guò)濾器可以實(shí)現(xiàn)URL重寫,通過(guò)重新URL可以實(shí)現(xiàn)隱藏實(shí)際路徑提高安全性,易于用戶記憶和鍵入,易于被搜索引擎收錄等優(yōu)點(diǎn),實(shí)現(xiàn)方式如下:

1.1.1 RewriterPathGatewayFilterFactory

RewritePath 網(wǎng)關(guān)過(guò)濾器工廠采用路徑正則表達(dá)式參數(shù)和替換參數(shù),使用Java正則表達(dá)式來(lái)靈活地重寫請(qǐng)求路徑。

spring:
  application:
    name: gateway-server
  cloud:
    gateway:
      # 路由規(guī)則
       routes:
          - id: product-service   # 路由ID,唯一,一般為各個(gè)服務(wù)名稱
           uri: http://localhost:7070/ #目標(biāo)URI,路由到微服務(wù)的地址
           predicates:
               # 匹配對(duì)應(yīng)的URL請(qǐng)求,將匹配到的請(qǐng)求追加在目標(biāo) URI 之后
               - Path=/product/** , /api-gateway/**
            filters:  # 網(wǎng)關(guān)過(guò)濾器
                # 將 /api-gateway/product/1 重寫為 /product/1
                - RewritePath=/api-gateway(?<segment>/?.*), $\{segment}
RewritePath=/api-gateway(?<segment>/?.*), $(segment)

1.1.2 PrefixPathGatewayFilterFactory

PrefixPath 網(wǎng)關(guān)過(guò)濾器工廠為匹配的 URI 添加指定前綴。

spring:
  application:
    name: gateway-server
  cloud:
    gateway:
      # 路由規(guī)則
       routes:
          - id: product-service   # 路由ID,唯一,一般為各個(gè)服務(wù)名稱
           uri: http://localhost:7070/ #目標(biāo)URI,路由到微服務(wù)的地址
           predicates:
               # 匹配對(duì)應(yīng)的URL請(qǐng)求,將匹配到的請(qǐng)求追加在目標(biāo) URI 之后
               - Path=/**
            filters:  # 網(wǎng)關(guān)過(guò)濾器
                # 將 /1 重寫為 /product/1
                - PrefixPath=/product
PrefixPath=/product

1.1.3 StripPrefixGatewayFilterFactory

StripPrefix 網(wǎng)關(guān)過(guò)濾器工廠采用一個(gè)參數(shù) StripPrefix,該參數(shù)表示在將請(qǐng)求發(fā)送到下游之前從請(qǐng)求中剝離的路徑個(gè)數(shù)。

spring:
  application:
    name: gateway-server
  cloud:
    gateway:
      # 路由規(guī)則
       routes:
           - id: product-service   # 路由ID,唯一,一般為各個(gè)服務(wù)名稱
           uri: http://localhost:7070/ #目標(biāo)URI,路由到微服務(wù)的地址
           predicates:
               # 匹配對(duì)應(yīng)的URL請(qǐng)求,將匹配到的請(qǐng)求追加在目標(biāo) URI 之后
               - Path=/**
           filters:  # 網(wǎng)關(guān)過(guò)濾器
                # 將 /api/123/product/1 重寫為 /product/1
                - StripPrefix=2
StripPrefix=2

1.1.4 SetPathGatewayFilterFactory

SetPath 網(wǎng)關(guān)過(guò)濾器工廠采用路徑模板參數(shù),它提供了一種通過(guò)允許模板化路徑段來(lái)操作請(qǐng)求路徑的簡(jiǎn)單方法,使用了SpringFramework中的URi模板,允許多個(gè)匹配段。

spring:
  application:
    name: gateway-server
  cloud:
    gateway:
      # 路由規(guī)則
       routes:
           - id: product-service   # 路由ID,唯一,一般為各個(gè)服務(wù)名稱
           uri: http://localhost:7070/ #目標(biāo)URI,路由到微服務(wù)的地址
           predicates:
               # 匹配對(duì)應(yīng)的URL請(qǐng)求,將匹配到的請(qǐng)求追加在目標(biāo) URI 之后
               - Path=/api/product/{segment}
            filters:  # 網(wǎng)關(guān)過(guò)濾器
                # 將 /api/product/1 重寫為 /product/1
                - SetPath=/product/{segment}
SetPath=/product/{segment}

1.2 Parameter參數(shù)過(guò)濾器

AddRequestParameter 網(wǎng)關(guān)過(guò)濾器工廠會(huì)將指定參數(shù)添加至匹配到的下游請(qǐng)求中。

spring:
  application:
    name: gateway-server
  cloud:
    gateway:
      # 路由規(guī)則
       routes:
           - id: product-service   # 路由ID,唯一,一般為各個(gè)服務(wù)名稱
           uri: http://localhost:7070/ #目標(biāo)URI,路由到微服務(wù)的地址
           predicates:
               # 匹配對(duì)應(yīng)的URL請(qǐng)求,將匹配到的請(qǐng)求追加在目標(biāo) URI 之后
               - Path=/api-gateway/**
            filters:  # 網(wǎng)關(guān)過(guò)濾器
                # 將 /api-gateway/product/1 重寫為 /product/1
                - RewritePath=/api-gateway(?<segment>/?.*), $\{segment}
                # 在下游請(qǐng)求中添加 flag=1
                - AddRequestParameter=flag, 1

1.3 Status 狀態(tài)過(guò)濾器

SetStatus 網(wǎng)關(guān)過(guò)濾器工廠采用單個(gè)狀態(tài)參數(shù),它必須為是有效的 Spring HttpStatus。它可以是整數(shù)404或枚舉NOT_FOUND的字符串表示。

spring:
  application:
    name: gateway-server
  cloud:
    gateway:
      # 路由規(guī)則
       routes:
           - id: product-service   # 路由ID,唯一,一般為各個(gè)服務(wù)名稱
           uri: http://localhost:7070/ #目標(biāo)URI,路由到微服務(wù)的地址
           predicates:
               # 匹配對(duì)應(yīng)的URL請(qǐng)求,將匹配到的請(qǐng)求追加在目標(biāo) URI 之后
               - Path=/api-gateway/**
            filters:  # 網(wǎng)關(guān)過(guò)濾器
                # 將 /api-gateway/product/1 重寫為 /product/1
                - RewritePath=/api-gateway(?<segment>/?.*), $\{segment}
                # 任何情況下,響應(yīng)的HTTP狀態(tài)都將設(shè)置為404
                - SetStatus=404 # 404 或者對(duì)應(yīng)的枚舉 NOT_FOUND
SetStatus=404

2. 自定義過(guò)濾器

即使 Spring Cloud Gateway 自帶許多實(shí)用的 GatewayFilter Factory、Gateway Filter、Global Filter,但是在很多情景下我們?nèi)匀幌M梢宰远x自己的過(guò)濾器,實(shí)現(xiàn)一些謹(jǐn)慎操作。

2.1 自定義網(wǎng)關(guān)過(guò)濾器

自定義網(wǎng)關(guān)過(guò)濾器需要實(shí)現(xiàn)以下兩個(gè)接口:GatewayFilter,Ordered。

public class CustomGatewayFilter implements GatewayFilter, Ordered {
    /**
     * 過(guò)濾器業(yè)務(wù)邏輯
     * @param exchange
     * @param chain
     * @return
     */
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        System.out.println("自定義網(wǎng)關(guān)過(guò)濾器被執(zhí)行");

        return chain.filter(exchange); // 繼續(xù)向下執(zhí)行
    }

    /**
     * 過(guò)濾器執(zhí)行順序,數(shù)值越小,優(yōu)先級(jí)越高
     * @return
     */
    @Override
    public int getOrder() {
        return 0;
    }
}

對(duì)自定義的過(guò)濾器進(jìn)行注冊(cè)

@Configuration
public class GatewayRoutesConfiguration {

    @Bean
    public RouteLocator routeLocator(RouteLocatorBuilder builder){
        return builder.routes().route(r -> r
                // 斷言(判斷條件)
                .path("/product/**")
                // 目標(biāo) URI ,路由到微服務(wù)的地址
                .uri("http://localhost:7070")
                // 注冊(cè)自定義網(wǎng)關(guān)過(guò)濾器
                .filters(new CustomGatewayFilter())
                // 路由 ID, 唯一
                .id("product-service")).build();
    }
}

2.2 自定義全局過(guò)濾器

自定義全局過(guò)濾器需要實(shí)現(xiàn)以下兩個(gè)接口:GlobalFilter, Ordered。通過(guò)全局過(guò)濾器可以實(shí)現(xiàn)全校校驗(yàn),安全性驗(yàn)證等功能。

創(chuàng)建過(guò)濾器,實(shí)現(xiàn)指定接口,添加@component注解即可,一個(gè)網(wǎng)關(guān)既有網(wǎng)關(guān)過(guò)濾器又有全局過(guò)濾器,則執(zhí)行順序,先執(zhí)行全局過(guò)濾器,后執(zhí)行網(wǎng)關(guān)過(guò)濾器
@Component
public class CustomGlobalFilter implements GlobalFilter, Ordered {
    /**
     * 過(guò)濾器業(yè)務(wù)邏輯
     * @param exchange
     * @param chain
     * @return
     */
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        System.out.println("自定義全局過(guò)濾器被執(zhí)行");
        return chain.filter(exchange); // 繼續(xù)向下執(zhí)行
    }

    /**
     * 過(guò)濾器執(zhí)行順序,數(shù)值越小,優(yōu)先級(jí)越高
     * @return
     */
    @Override
    public int getOrder() {
        return 0;
    }
}

2.3 統(tǒng)一鑒權(quán)

在網(wǎng)關(guān)過(guò)濾器中通過(guò)token判斷用戶是否登錄,完成一個(gè)統(tǒng)一的鑒權(quán)案例

@Component
public class AccessFilter implements GlobalFilter, Ordered {
    private Logger logger = (Logger) LoggerFactory.getLogger(AccessFilter.class);

    /**
     *  過(guò)濾器業(yè)務(wù)邏輯
     * @param exchange
     * @param chain
     * @return
     */
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // 獲取請(qǐng)求參數(shù)
        String token = exchange.getRequest().getQueryParams().getFirst("token");
        // 業(yè)務(wù)邏輯處理
        if(StringUtils.isBlank(token)){
            logger.warning("token is null ...");
            ServerHttpResponse response = exchange.getResponse();
            // 響應(yīng)類型
            response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
            // 響應(yīng)狀態(tài)碼,HTTP 401 錯(cuò)誤代表用戶沒(méi)有訪問(wèn)權(quán)限
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            // 響應(yīng)內(nèi)容
            String message = "{\"message\":\"" + HttpStatus.UNAUTHORIZED.getReasonPhrase() + "\"}";
            DataBuffer buffer = response.bufferFactory().wrap(message.getBytes());
            // 請(qǐng)求結(jié)束,不在繼續(xù)向下請(qǐng)求
            return response.writeWith(Mono.just(buffer));
        }
        // 使用token進(jìn)行身份驗(yàn)證
        logger.info("token is OK!");
        return chain.filter(exchange);
    }

    /**
     * 過(guò)濾器執(zhí)行順序,數(shù)值越小,優(yōu)先級(jí)越高
     * @return
     */
    @Override
    public int getOrder() {
        return 1;
    }
}
image.png

image.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容