网关是将所有面向用户的服务接口统一管理的代理服务器,所有内部服务的远程调用都是在局域网内部,而网关是在公网中。
一、依赖
通过访问网关调用项目中的服务,需要使用Eureka,网关服务器需要在Eureka服务注册它自己,本身也就是一个Eureka Client。
远程调用服务自然也离不开熔断降级的保护机制,使用Hystrix
网关是对所有访问的统一入口,面对恶意攻击,大量并发的情况,通常使用令牌桶机制来处理,令牌储存在redis中。
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.3.12.RELEASE</version> </parent> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Hoxton.SR12</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> </dependency> </dependencies>
二、基本配置
gateway解析自己配置时,- 代表了创建一个对象:
id: 路由名称
uri: 调用的服务主机名
predicates:代理地址
代理本身只解析主机名ip端口号,和代理地址做拼接,需要手动将/abc去除。
Vue3中代理配置也一样:
Filter:
因为所有Filter都以GatewayFilterFactory结尾,所有该结尾省略不写。
- StripPrefix=1
//简写形式 name =StripPrefixGatewayFilterFactory,参数为1
- name: RequestRateLimiter //通用的写法
args:...
server: port: 9999 eureka: client: service-url: defaultZone: http://localhost:8761/eureka/ spring: redis: host: localhost application: name: cloud-gateway cloud: gateway: discovery: locator: enabled: false lower-case-service-id: true routes: - id: rateLimiter uri: lb://application-service predicates: - Path=/abc/** filters: - StripPrefix=1
三、令牌桶过滤器
实现KeyResolver接口的resolve()方法
@Component public class MyKeyResolver implements KeyResolver { @Override public Mono<String> resolve(ServerWebExchange exchange) { String ip = exchange.getRequest() .getRemoteAddress() .getAddress() .getHostAddress(); return Mono.just(ip); } }
filters: - StripPrefix=1 - name: RequestRateLimiter args: keyResolver: '#{@myKeyResolver}' # 表达式, #{} 从容器找对象, @beanId redis-rate-limiter.replenishRate: 1 # 每秒令牌生成速率 redis-rate-limiter.burstCapacity: 2 # 令牌桶容量上限
四、熔断降级过滤器
配置HystrixGatewayFilterFactory对象,自定义降级的uri
filters: - StripPrefix=1 - name: RequestRateLimiter args: keyResolver: '#{@myKeyResolver}' # 表达式, #{} 从容器找对象, @beanId redis-rate-limiter.replenishRate: 1 # 每秒令牌生成速率 redis-rate-limiter.burstCapacity: 2 # 令牌桶容量上限 - name: Hystrix args: name: fallback # 随意定义的名称。相当于@HystrixCommand注解中的commandKey属性。 fallbackUri: forward:/fallback # 如果转发
五、全局过滤器和自定义过滤器:
全局过滤器:
实现GlobalFilter的filter()方法
@Component public class MyGlobalFilter implements GlobalFilter { /** * 过滤方法。 * 实现上,只有唯一的要求。必须调用方法chain.filter(exchange),并把方法的返回值,返回。 * @param exchange * @param chain * @return */ @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { System.out.println("前置全局过滤"); Mono<Void> result = chain.filter(exchange); System.out.println("后置全局过滤"); return result; } }
自定义过滤器:
1.仿照其他Gateway提供的过滤器,创建一个LoggerFilterGatewayFilterFactory继承AbstractGatewayFilterFactory<LoggerFilterGatewayFilterFactory.Config>
@Component public class LoggerFilterGatewayFilterFactory extends AbstractGatewayFilterFactory<LoggerFilterGatewayFilterFactory.Config> { /** * 建议提供2个构造方法。一个无参数。一个有参数,参数类型就是当前类型中的Config静态内部类的类对象类型。 * 父类型,可以帮助解析配置文件,并创建Config对象。 */ public LoggerFilterGatewayFilterFactory(){ this(Config.class); } public LoggerFilterGatewayFilterFactory(Class<Config> configClass){ super(configClass); } /** * 如果需要简化配置方案。提供方法shortcutFieldOrder * 有当前方法,配置文件使用,可以简化配置为 LoggerFilter=abc * 没有当前方法,配置文件完整编写,内容是: * name: LoggerFilter * args: * remark: abc */ @Override public List<String> shortcutFieldOrder() { return Arrays.asList("remark"); } /** * 创建网关过滤器的方法。 * @param config 就是配置文件中的内容,就是当前类型中的静态内部类对象。 * @return 一般使用匿名内部类,创建GatewayFilter接口的实现对象。 */ @Override public GatewayFilter apply(Config config) { return new GatewayFilter() { /** * 过滤方法。要求必须调用chain.filter(exchange),并返回方法的返回结果 * @param exchange * @param chain * @return */ @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { System.out.println("前置 - 日志过滤器 - config.remark = " + config.getRemark()); Mono<Void> result = chain.filter(exchange); System.out.println("后置 - 日志过滤器 - config.remark = " + config.getRemark()); return result; } }; } /** * 定义静态内部类,作为配置对象 * 定义的每个属性,都是用于在配置文件中配置的对应属性。 * 必须提供getter和setter方法。 */ public static class Config{ private String remark; public String getRemark() { return remark; } public void setRemark(String remark) { this.remark = remark; } } }
2.配置文件编写该自定义过滤器对象配置信息
filters: - StripPrefix=1 - name: RequestRateLimiter args: keyResolver: '#{@myKeyResolver}' # 表达式, #{} 从容器找对象, @beanId redis-rate-limiter.replenishRate: 1 # 每秒令牌生成速率 redis-rate-limiter.burstCapacity: 2 # 令牌桶容量上限 - name: Hystrix args: name: fallback # 随意定义的名称。相当于@HystrixCommand注解中的commandKey属性。 fallbackUri: forward:/fallback # 如果转发 - name: LoggerFilter args: remark: fullyTestGatewayFilter