4-服務網關Gateway_自定義過濾器學習筆記(2020.3.31)
前言:
Spring Cloud Gateway 已經內置了很多實用的過濾器,但並不能完全滿足我們的需求。本文我們就來實現自定義過濾器。
用於常見的過濾請求, token驗證, 請求參數驗證什麼的。
1.Filter 的生命週期
Spring Cloud Gateway 的 Filter 的生命週期不像 Zuul 的那麼豐富,它只有兩個:“pre” 和 “post”。
“pre” 和 “post” 分別會在請求被執行前調用和被執行後調用,和 Zuul Filter 或 Spring Interceptor 中相關生命週期類似,但在形式上有些不一樣。
Zuul 的 Filter 是通過
filterType()
方法來指定,一個 Filter 只能對應一種類型,要麼是 “pre” 要麼是 “post”。Spring Interceptor 是通過重寫HandlerInterceptor
中的三個方法來實現的。而 Spring Cloud Gateway 基於 Project Reactor 和 WebFlux,採用響應式編程風格,打開它的 Filter 的接口GatewayFilter
你會發現它只有一個方法filter
。下面我們就來實現一下自定義過濾器, 對請求頭的token進行認證。
自定義過濾器需要實現
GatewayFilter
和Ordered
。其中GatewayFilter
中的這個方法就是用來實現你的自定義的邏輯的
Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain);
而
Ordered
中的int getOrder()
方法是來給過濾器設定優先級別的,值越大則優先級越低。
1.1 自定義普通過濾器
/**
* 此過濾器功能爲計算請求完成時間
*/
public class MyFilter implements GatewayFilter, Ordered {
private static final String ELAPSED_TIME_BEGIN = "elapsedTimeBegin";
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
exchange.getAttributes().put(ELAPSED_TIME_BEGIN, System.currentTimeMillis());
return chain.filter(exchange).then(
Mono.fromRunnable(() -> {
Long startTime = exchange.getAttribute(ELAPSED_TIME_BEGIN);
if (startTime != null) {
System.out.println(exchange.getRequest().getURI().getRawPath() + ": " + (System.currentTimeMillis() - startTime) + "ms");
}
})
);
}
/*
*過濾器存在優先級,order越大,優先級越低
*/
@Override
public int getOrder() {
return Ordered.LOWEST_PRECEDENCE;
}
}
定義好
MyFilter
以後,其需要跟Route
綁定使用,不能在application.yml
文件中配置使用
@Bean
public RouteLocator routeLocator(RouteLocatorBuilder builder) {
return builder.routes().route(r ->
r.path("/abc/**")
//去掉前綴1節
.filters(p->p.stripPrefix(1))
//轉發路由
.uri("lb://eureka-client")
//註冊自定義過濾器
.filters(new MyFilter())
//給定id
.id("user-service")
).build();
}
1.2 自定義全局過濾器
自定義過濾器, 假設對請求頭的token進行認證。
/**
* @Author: zhihao
* @Date: 2020/3/31 17:38
* @Description: 自定義過濾器
* @Versions 1.0
**/
@Component //交給框架管理
public class MyGatewayFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
//1.獲取請求對象
ServerHttpRequest request = exchange.getRequest();
//2.獲取請求頭Authenticate
List<String> authenticate = request.getHeaders().get("Authenticate");
if (null == authenticate || authenticate.isEmpty()) {
//說明Authenticate爲空,返回錯誤碼,阻止通過網關路由
ServerHttpResponse response = exchange.getResponse();
Map<String,String> resultMap = new LinkedHashMap<>();
resultMap.put("code", "401");
resultMap.put("message", "沒有token");
String jsonStr = JSONUtil.toJsonStr(resultMap);
//將錯誤信息輸出頁面
DataBuffer dataBuffer = response.bufferFactory().wrap(jsonStr.getBytes());
response.setStatusCode(HttpStatus.UNAUTHORIZED); //狀態碼
response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
Mono<Void> mono = response.writeWith(Mono.just(dataBuffer));
return mono;
//return response.setComplete();
}
//......可以通過
String[] strings = authenticate.toArray(new String[authenticate.size()]);
String str = strings[0];
return chain.filter(exchange);
}
@Override
public int getOrder() {
//值越大則優先級越低。
return -1;
}
}
er(exchange);
}
@Override
public int getOrder() {
//值越大則優先級越低。
return -1;
}
}
1