天天看點

Nacos網關gateway的斷言,自定義斷言,過濾器使用

作者:沒得感情的西瓜

接上次網關的初步搭架成功後,看看斷言和過濾器的如何操作。

上篇文章環境搭建已經ok,這次是在上篇的基礎上開始操作。

上篇說了斷言主要是配置檔案中的application-dev.properties配置檔案中spring.cloud.gateway.routes[0].predicates[0]的屬性配置,上次我們隻使用Path路徑的斷言,其實還有很多關鍵字可以使用

#設定路由斷言,代理servicerId為provider-xg的/provider-xg/路徑
spring.cloud.gateway.routes[0].predicates[0]=Path=/provider-route/**           

先搭好環境:Nacos注冊中心,調用服務

不清楚的朋友可以看看前面的文章

Nacos網關gateway的斷言,自定義斷言,過濾器使用

開始根據規則來進行斷言

因為規則太多我把對應規則的成功例子列出,測試幾個,有興趣的朋友可以自行測試其他。

#設定路由斷言
#Path 代表路徑斷言
spring.cloud.gateway.routes[0].predicates[0]=Path=/provider-route/**
#After 代表時間之後都可以通路的斷言
spring.cloud.gateway.routes[0].predicates[1]=After=2022-08-31T23:59:59.789+08:00[Asia/Shanghai]
#After 代表時間之前都可以通路的斷言
spring.cloud.gateway.routes[0].predicates[2]=Before=2022-12-31T23:59:59.789+08:00[Asia/Shanghai]
#Method 代表支援方法類型,可支援多個,逗号分隔
spring.cloud.gateway.routes[0].predicates[3]=Method=Get,Post
#RemoteAddr 代表支援ip的斷言支援多個,逗号分隔
spring.cloud.gateway.routes[0].predicates[4]=RemoteAddr=10.45.12.61,10.45.12.63
#自定義斷言
spring.cloud.gateway.routes[0].predicates[5]=Test=dxg
#請求轉發時會攔截路徑/provider-route開頭的,并且去掉/provider-route再開始轉發到對應微服務接口,1的意思去掉一個字首,2就是去掉倆個
spring.cloud.gateway.routes[0].filters[0]=StripPrefix=1           

我們測試下時間斷言:

把After改為目前時間之後,因為時間沒到,會通路失敗,應該通路不了,改為今年12月

spring.cloud.gateway.routes[0].predicates[1]=After=2022-12-31T23:59:59.789+08:00[Asia/Shanghai]           

通路測試:正常報錯,斷言成功,其他斷言大家自行測試

Nacos網關gateway的斷言,自定義斷言,過濾器使用

下面列出我目前接觸到的規則:

  • Path 代表路徑斷言
  • After 代表時間之後都可以通路的斷言
  • After 代表時間之前都可以通路的斷言
  • Method 代表支援方法類型,可支援多個,逗号分隔
  • RemoteAddr 代表支援遠端位址的斷言支援多個,逗号分隔
  • Cookie:接收兩個參數, cookie 名字和一個正規表達式。判斷請求cookie是否具有給定名稱且值與正規表達式比對。
spring.cloud.gateway.routes[0].predicates[3]=Cookie=chocolate, ch.           
  • Header :接收兩個參數,标題名稱和正規表達式。 判斷請求Header 是否具有給定名稱且值與正規表達式比對。 key value
spring.cloud.gateway.routes[0].predicates[n]=Header=X-Request-Id, \d+           
  • Host :接收一個參數,主機名模式。判斷請求的Host 是否滿足比對規則。
spring.cloud.gateway.routes[0].predicates[n]=Host=**.hostName.org           
  • Query :接收兩個參數,請求 param 和正規表達式, 判斷請求參數是否具有給定名稱且值與正規表達式比對。
spring.cloud.gateway.routes[0].predicates[n]=Query=xg, dag.           
  • 基于路由權重的斷言工廠 Weight:接收一個 [ 組名 , 權重 ], 然後對于同一個組内的路由按照權重轉發
spring.cloud.gateway.routes[0].predicates[n]=Weight= groupName, 9           

如果上述規則不滿足需求的話還可以自定義斷言

先說一個場景,隻支援某個人來通路接口,這時候我們需要定制化一個斷言。

自定義斷言有幾個要求:

1.必須繼承AbstractRoutePredicateFactory

2.類名稱必須xxx加上RoutePredicateFactory作為結尾,其中xxx就是路由斷言新增的配置規則,可以在斷言中添加

3.shortcutFieldOrder方法綁定路由中的配置,即可去讀

4.通過apply進行邏輯判斷 true就是比對成功 false比對失敗

現在貼上實作類代碼:

package com.gateway.predicate;

import lombok.Data;
import lombok.NoArgsConstructor;
import org.apache.commons.lang.StringUtils;
import org.springframework.cloud.gateway.handler.predicate.AbstractRoutePredicateFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;

import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;

/**
 * @author xg
 */
@Component
public class TestRoutePredicateFactory extends AbstractRoutePredicateFactory<TestRoutePredicateFactory.Config> {
    public TestRoutePredicateFactory() {
        super(TestRoutePredicateFactory.Config.class);
    }

    //讀取配置檔案中的内容并配置給配置類中的屬性,即新增的斷言配置項
    @Override
    public List<String> shortcutFieldOrder() {
        return Arrays.asList("name");
    }

    @Override
    public Predicate<ServerWebExchange> apply(TestRoutePredicateFactory.Config config) {
        return (exchange) -> {
          // 從請求中擷取配置項,也可配置在其他地方擷取,看個人需求
            String name = exchange.getRequest().getQueryParams().getFirst("name");
            if(StringUtils.isNotEmpty(name)){
               if(name.equals(config.getName())) {
                   return true;
               }
            }
            return false;
        };
    }

    @Data
    @NoArgsConstructor
    public static class Config{
        private String name;
    }
}
           

根據自定義斷言類建立,我們就産生新的斷言規則關鍵字,這個關鍵字其實就是自定義斷言名稱去掉RoutePredicateFactory的字元串也就是Test,路由配置為下面

#自定義斷言
spring.cloud.gateway.routes[0].predicates[5]=Test=dxg           

現在我們測試帶個name交xg的,我們配置的是dxg,是以會通路失敗

Nacos網關gateway的斷言,自定義斷言,過濾器使用

接下來測試dxg,這次應該成功:

Nacos網關gateway的斷言,自定義斷言,過濾器使用

請求成功

自定義斷言結束。

接下來看看過濾器

過濾器

定義全局過濾器,需要繼承倆個接口GlobalFilter, Ordered,

GlobalFilter是具體過濾邏輯,Ordered是定義過濾器的順序,就是說可以定義多個過濾器,這個用來指定過濾器的執行順序。

package com.gateway.filters;

import com.alibaba.cloud.commons.lang.StringUtils;
import com.alibaba.fastjson.JSONObject;
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.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.nio.charset.StandardCharsets;

/**
 * @author xg
 */
@Component
public class TestFilter implements GlobalFilter, Ordered {

    /**
     * 過濾器的具體邏輯
     * @param exchange
     * @param chain
     * @return
     */
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();
        String token = request.getQueryParams().getFirst("token");

        // 判斷token是否符合條件,正确則進入接口調用流程。否則不合法請求,直接傳回
        if(StringUtils.isNotEmpty(token)) {
            // token的具體判斷邏輯
            if("1q2w3e4r".equals(token)) {
                // 校驗通過,走接下來接口邏輯或者其他過濾器
                return chain.filter(exchange);
            }
        }

        // 不合法token,直接傳回,提示沒有權限
        response.setStatusCode(HttpStatus.UNAUTHORIZED);
        response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
        DataBuffer buffer = response.bufferFactory().wrap(JSONObject.toJSONString("token is illegal.").getBytes(StandardCharsets.UTF_8));

        return response.writeWith(Flux.just(buffer));
    }

    /**
     * 用來定義過濾器的執行順序,升序執行
     * @return
     */
    @Override
    public int getOrder() {
        return 0;
    }
}
           

我們定義的過濾器必須攜帶token,而且必須符合我們定義的規則才可通過,否則屬于不合法的請求,不允許通路。

我們随便攜帶了token,不符合條件來通路試試:

http://10.45.12.63:8099/provider-route/provider/get?name=dxg&token=1234

Nacos網關gateway的斷言,自定義斷言,過濾器使用

直接報token不合法,接下來我們試試合法的token

http://10.45.12.63:8099/provider-route/provider/get?name=dxg&token=1q2w3e4r

Nacos網關gateway的斷言,自定義斷言,過濾器使用

請求成功,到此,我們的過濾器就建立成功了。當然我們的邏輯很是簡單,真正的過濾器可以做很多功能,token鑒權,日志列印等等。有興趣可以自己去試試。如果覺得不錯,希望大家點贊加關注哦。

Nacos網關gateway的斷言,自定義斷言,過濾器使用
  • 事物的精粹,總在它離去時方才顯現
  • 願大家珍惜所擁有的,不負韶華,以夢為馬,曆盡千帆,歸來仍是少年。

繼續閱讀