7.Cloud-GateWay

0.概述

https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.2.1.RELEASE/reference/html/

1.入门配置

  1.1 POM

 <!--新增gateway-->
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId>
</dependency><!-- nacos -->
<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

  1.2 YML

server:port: 9527
spring:application:name: cloud-gatewaycloud:gateway:discovery:locator:enabled: trueroutes:- id: payment-routeuri: lb://cloud-order-servicepredicates:- Path=/v2/order/**filters:- StripPrefix=1nacos:discovery:server-addr: 192.168.2.18:8848inetutils:ignored-interfaces: ['VMware.*']

  1.3 主启动类

@SpringBootApplication
public class GateWayMain {public static void main(String[] args) {SpringApplication.run(GateWayMain.class, args);}
}

  1.4 测试

localhost:9527/v2/order/

2.Predicate的使用

pring:cloud:gateway:routes:- id: before_routeuri: lb://cloud-order-servicepredicates:# 在某个时间之前的请求才会被转发到 http://localhost:8001,- Before=2017-01-20T17:42:47.789+08:00[Asia/Shanghai]# 在某个时间之后的请求才会被转发#   - After=2017-01-20T17:42:47.789+08:00[Asia/Shanghai]# 在某个时间段之间的才会被转发#   - Between=2017-01-20T17:42:47.789+08:00[Asia/Shanghai], 2017-01-21T17:42:47.789+08:00[Asia/Shanghai]# 名为chocolate的表单或者满足正则ch.p的表单才会被匹配到进行请求转发#   - Cookie=chocolate, ch.p# 携带参数X-Request-Id或者满足\d+的请求头才会匹配#   - Header=X-Request-Id, \d+# 按Host主机名匹配#   - Host=qiying.com:8080# 按请求方法进行匹配,只有GET方法才会匹配#   - Method=GET# 按请求路径进行匹配#   - Path=/app/{path}filters:# 在请求路径前加上自定义的路径#   - PrefixPath=/app# 重写请求路径# 访问localhost:8080/test, 请求会转发到localhost:8001/app/test#   - RewritePath=/test, /app/test#   - RewritePath=(?<oldPath>^/), /app$\{oldPath}# 通过模板设置路径#   - SetPath=/app/{path}

3.Filter的使用

  3.1 自定义全局过滤器

import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;import java.util.Date;@Component
@Slf4j
public class MyLogGateWayFilter implements GlobalFilter, Ordered {@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {log.info("*********come in MyLogGateWayFilter: "+new Date());String name = exchange.getRequest().getQueryParams().getFirst("username");if(StringUtils.isEmpty(name)){log.info("*****用户名为Null 非法用户,(┬_┬)");exchange.getResponse().setRawStatusCode(HttpStatus.NOT_ACCEPTABLE.value());return exchange.getResponse().setComplete();}return chain.filter(exchange);}@Overridepublic int getOrder() {return 0;}
}

  3.2 令牌桶算法限流

    1) YML配置

spring:application:name: cloud-gatewaycloud:gateway:     routes:- id: cloud-order-serviceuri: lb://cloud-order-servicepredicates:- Path=/v2/**- After=2024-02-17T10:41:00.000+08:00[Asia/Shanghai]filters:- name: StripPrefixargs:parts: 1- name: RequestRateLimiterargs:keyResolver: '#{@myKeyResolver}'redis-rate-limiter.replenishRate: 1 #生产令牌速度,每秒多少个redis-rate-limiter.burstCapacity: 5 #令牌桶容量nacos:discovery:server-addr: 192.168.2.18:8848inetutils:ignored-interfaces: ['VMware.*']redis:host: 192.168.2.18password: 123456

    2) 创建MyKeyResolver类

import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;@Component
public class MyKeyResolver implements KeyResolver {@Overridepublic Mono<String> resolve(ServerWebExchange exchange) {String address = exchange.getRequest().getRemoteAddress().getAddress().getHostAddress();return Mono.just(address);}
}

    3) request_rate_limiter.lua

local tokens_key = KEYS[1]
local timestamp_key = KEYS[2]
--redis.log(redis.LOG_WARNING, "tokens_key " .. tokens_key)local rate = tonumber(ARGV[1])
local capacity = tonumber(ARGV[2])
local now = tonumber(ARGV[3])
local requested = tonumber(ARGV[4])local fill_time = capacity/rate
local ttl = math.floor(fill_time*2)--redis.log(redis.LOG_WARNING, "rate " .. ARGV[1])
--redis.log(redis.LOG_WARNING, "capacity " .. ARGV[2])
--redis.log(redis.LOG_WARNING, "now " .. ARGV[3])
--redis.log(redis.LOG_WARNING, "requested " .. ARGV[4])
--redis.log(redis.LOG_WARNING, "filltime " .. fill_time)
--redis.log(redis.LOG_WARNING, "ttl " .. ttl)local last_tokens = tonumber(redis.call("get", tokens_key))
if last_tokens == nil thenlast_tokens = capacity
end
--redis.log(redis.LOG_WARNING, "last_tokens " .. last_tokens)local last_refreshed = tonumber(redis.call("get", timestamp_key))
if last_refreshed == nil thenlast_refreshed = 0
end
--redis.log(redis.LOG_WARNING, "last_refreshed " .. last_refreshed)local delta = math.max(0, now-last_refreshed)
local filled_tokens = math.min(capacity, last_tokens+(delta*rate))
local allowed = filled_tokens >= requested
local new_tokens = filled_tokens
local allowed_num = 0
if allowed thennew_tokens = filled_tokens - requestedallowed_num = 1
end--redis.log(redis.LOG_WARNING, "delta " .. delta)
--redis.log(redis.LOG_WARNING, "filled_tokens " .. filled_tokens)
--redis.log(redis.LOG_WARNING, "allowed_num " .. allowed_num)
--redis.log(redis.LOG_WARNING, "new_tokens " .. new_tokens)redis.call("setex", tokens_key, ttl, new_tokens)
redis.call("setex", timestamp_key, ttl, now)return { allowed_num, new_tokens }

    4) 如果请求每秒超过5个,将无法访问, 执行的类,RedisRateLimiter.isAllowed

  3.3 自定义断言过滤器

    1) 创建过滤器

import lombok.extern.slf4j.Slf4j;
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.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;import java.util.Arrays;
import java.util.List;@Component
@Slf4j
public class XXGatewayFilterFactory extends AbstractGatewayFilterFactory<XXGatewayFilterFactory.Config> {public XXGatewayFilterFactory(){super(Config.class);}@Overridepublic List<String> shortcutFieldOrder() {return Arrays.asList("path");}@Overridepublic GatewayFilter apply(Config config) {return new GatewayFilter() {@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {log.info("xx-GatewayFilter-filter");return chain.filter(exchange);}};}public static class Config{public String getPath() {return path;}public void setPath(String path) {this.path = path;}private String path;}
}

    2) YML

spring:cloud:gateway:       routes:- id: cloud-order-serviceuri: lb://cloud-order-servicepredicates:- Path=/v2/**- After=2024-02-17T10:41:00.000+08:00[Asia/Shanghai]filters: - name: XX

  3.4 

4.跨域

spring:application:name: cloud-gatewaycloud:gateway:globalcors:cors-configurations:'[/**]':allowedHeaders: "*"allowedOrigins: "*"allowedMethods: "*"