網(wǎng)站建設(shè)方案新聞鄭州網(wǎng)絡(luò)營(yíng)銷(xiāo)公司
目錄
一、概覽?
二、通過(guò)GatewayFilter實(shí)現(xiàn)
三、繼承AbstractGatewayFilterFactory
一、概覽?
???????當(dāng)使用Spring Cloud Gateway構(gòu)建API網(wǎng)關(guān)時(shí),可以利用Spring Cloud Gateway提供的內(nèi)置過(guò)濾器(filter)來(lái)實(shí)現(xiàn)對(duì)請(qǐng)求的處理和響應(yīng)的處理。過(guò)濾器可以在請(qǐng)求被路由之前或之后被執(zhí)行,它可以用于修改請(qǐng)求和響應(yīng)內(nèi)容、記錄請(qǐng)求日志、校驗(yàn)請(qǐng)求參數(shù)、鑒權(quán)等等。如果內(nèi)置的過(guò)濾器不能滿(mǎn)足需求,可以自定義過(guò)濾器。
????????之前博客已經(jīng)介紹了Spring Cloud Gateway內(nèi)置過(guò)濾器的使用方法和示例,具體可以參考:https://blog.csdn.net/qq_41061437/article/details/128069622
????????本篇博客將重點(diǎn)介紹如何編寫(xiě)自定義的過(guò)濾器,并將其應(yīng)用到Spring Cloud Gateway中。將使用Java編程語(yǔ)言,以及Spring Boot和Spring Cloud Gateway框架。將通過(guò)一個(gè)示例來(lái)演示如何實(shí)現(xiàn)一個(gè)自定義過(guò)濾器,講解自定義過(guò)濾器的實(shí)現(xiàn)方法、配置方法和使用方法。
二、通過(guò)GatewayFilter實(shí)現(xiàn)
????????SpringCloudGateWay項(xiàng)目參考:SpringCloudGateway--自動(dòng)路由映射與手動(dòng)路由映射_雨欲語(yǔ)的博客-CSDN博客
? ? ? ? 使用GatewayFilter實(shí)現(xiàn)需要implements GatewayFilter和Ordered,首先在gateway項(xiàng)目中新建MyOneGatewayFilter類(lèi):
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.core.Ordered;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;import java.net.URI;@Component
public class MyOneGatewayFilter implements GatewayFilter, Ordered {@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {// 獲取請(qǐng)求路徑String path = exchange.getRequest().getPath().toString();URI uri = exchange.getRequest().getURI();System.err.println(String.format("獲取到請(qǐng)求路徑:%s", uri.toString()));// 如果請(qǐng)求路徑以“/v1”開(kāi)頭,則截取掉第一個(gè)路徑段if (path.startsWith("/v1")) {path = path.substring("/v1".length());}// 創(chuàng)建新的請(qǐng)求對(duì)象,并將新路徑設(shè)置為請(qǐng)求路徑ServerHttpRequest newRequest = exchange.getRequest().mutate().path(path).build();// 使用新請(qǐng)求對(duì)象創(chuàng)建新的ServerWebExchange對(duì)象ServerWebExchange newExchange = exchange.mutate().request(newRequest).build();System.err.println(String.format("獲取到新的請(qǐng)求路徑:%s", newExchange.getRequest().getURI()));// 繼續(xù)執(zhí)行過(guò)濾器鏈return chain.filter(newExchange);}@Overridepublic int getOrder() {return 0;}
}
? ? ? ? 新建GatewayConfig類(lèi),
import com.littledyf.filter.MyOneGatewayFilter;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class GatewayConfig {@Value("${server.port}")private String port;@Beanpublic RouteLocator customerRouteLocator(RouteLocatorBuilder builder) {return builder.routes().route(r -> r.path("/v1/**").filters(f -> f.filter(new MyOneGatewayFilter())).uri("http://localhost:" + port)).build();}}
? ? ? ? yml文件使用之前的:
server:port: 9999
spring:application:name: service-gatewaycloud: # 配置Spring Cloud相關(guān)屬性gateway:discovery: # 配置網(wǎng)關(guān)發(fā)現(xiàn)機(jī)制locator: # 配置處理機(jī)制enabled: false # 開(kāi)啟網(wǎng)關(guān)自動(dòng)映射處理邏輯lower-case-service-id: true # 開(kāi)啟小寫(xiě)轉(zhuǎn)換filter:secure-headers:disable:- strict-transport-security- x-download-optionsroutes: # 配置網(wǎng)關(guān)中的一個(gè)完整路由,包括命名,地址,謂詞集合(規(guī)則),過(guò)濾器集合- id: service-one # 路由定義的命名,唯一即可。命名規(guī)則符合Java中的變量符命名規(guī)則uri: lb://service-one # 當(dāng)前路由定義對(duì)應(yīng)的微服務(wù)轉(zhuǎn)發(fā)地址,lb - 代表loadbalancepredicates: # 配置謂詞集合- Path=/service/**filters:- StripPrefix=1nacos:username: nacospassword: nacosdiscovery:server-addr: 127.0.0.1group: devnamespace: devmetadata:version: v1.0.0
? ? ? ? 啟動(dòng)項(xiàng)目訪(fǎng)問(wèn)測(cè)試:http://localhost:9999/v1/service/nacos/test
? ? ? ? 可以看到如果是以v1開(kāi)頭的,會(huì)直接進(jìn)入到我們自定義的MyOneGatewayFilter過(guò)濾器中,如果直接service開(kāi)頭,則直接走內(nèi)置過(guò)濾器。
三、繼承AbstractGatewayFilterFactory
? ? ? ? xxxxGatewayFilterFactory是符合內(nèi)置過(guò)濾器原則的,所有已經(jīng)實(shí)現(xiàn)的內(nèi)置過(guò)濾器都是按照這種方式進(jìn)行的,這里就是仿照內(nèi)置過(guò)濾器編寫(xiě),編寫(xiě)MyTwoGatewayFilterFactory類(lèi):
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.cloud.gateway.support.GatewayToStringStyler;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;import java.net.URI;
import java.util.Arrays;
import java.util.List;@Component
public class MyTwoGatewayFilterFactory extends AbstractGatewayFilterFactory<MyTwoGatewayFilterFactory.Config> {public MyTwoGatewayFilterFactory() {super(MyTwoGatewayFilterFactory.Config.class);}@Overridepublic List<String> shortcutFieldOrder() {return Arrays.asList("name");}@Overridepublic GatewayFilter apply(MyTwoGatewayFilterFactory.Config config) {return new GatewayFilter() {@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {// 獲取請(qǐng)求路徑URI uri = exchange.getRequest().getURI();System.err.println(String.format("獲取到請(qǐng)求路徑:%s", uri));//System.err.println(String.format("配置屬性:%s", config.getName()));String path = exchange.getRequest().getPath().toString();// 如果請(qǐng)求路徑以“/xxx”開(kāi)頭,則截取掉第一個(gè)路徑段,xxx是配置文件中的name屬性if (path.startsWith("/" + config.getName())) {path = path.substring(("/" + config.getName()).length());}else {throw new IllegalStateException("CustomGatewayFilter is not enabled");}// 創(chuàng)建新的請(qǐng)求對(duì)象,并將新路徑設(shè)置為請(qǐng)求路徑ServerHttpRequest newRequest = exchange.getRequest().mutate().path(path).build();// 使用新請(qǐng)求對(duì)象創(chuàng)建新的ServerWebExchange對(duì)象ServerWebExchange newExchange = exchange.mutate().request(newRequest).build();System.err.println(String.format("獲取到新的請(qǐng)求路徑:%s", newExchange.getRequest().getURI()));return chain.filter(newExchange);}@Overridepublic String toString() {return GatewayToStringStyler.filterToStringCreator(MyTwoGatewayFilterFactory.this).toString();}};}public static class Config {private String name;public Config() {}public String getName() {return this.name;}public void setName(String name) {this.name = name;}}
}
? ? ? ? 在配置文件中加上剛編寫(xiě)的自定義過(guò)濾器名:
server:port: 9999
spring:application:name: service-gatewaycloud: # 配置Spring Cloud相關(guān)屬性gateway:discovery: # 配置網(wǎng)關(guān)發(fā)現(xiàn)機(jī)制locator: # 配置處理機(jī)制enabled: false # 開(kāi)啟網(wǎng)關(guān)自動(dòng)映射處理邏輯lower-case-service-id: true # 開(kāi)啟小寫(xiě)轉(zhuǎn)換filter:secure-headers:disable:- strict-transport-security- x-download-optionsroutes: # 配置網(wǎng)關(guān)中的一個(gè)完整路由,包括命名,地址,謂詞集合(規(guī)則),過(guò)濾器集合- id: service-one # 路由定義的命名,唯一即可。命名規(guī)則符合Java中的變量符命名規(guī)則uri: lb://service-one # 當(dāng)前路由定義對(duì)應(yīng)的微服務(wù)轉(zhuǎn)發(fā)地址,lb - 代表loadbalancepredicates: # 配置謂詞集合- Path=/service/**filters:- StripPrefix=1- MyTwo=apinacos:username: nacospassword: nacosdiscovery:server-addr: 127.0.0.1group: devnamespace: devmetadata:version: v1.0.0
? ? ? ? 測(cè)試:http://localhost:9999/service/api/nacos/test
? ? ? ? 如果不包含我們定義的api,則直接報(bào)錯(cuò):
? ? ? ? 這只是簡(jiǎn)單展示了自定義過(guò)濾器的功能,實(shí)際能實(shí)現(xiàn)很多復(fù)雜功能。比如進(jìn)行鑒權(quán)、黑白名單過(guò)濾等等。