Spring Cloud Gateway入门

目录

1、什么是网关

Nginx 和 Gateway 的区别:

2、断言和GateWay过滤器

2.1、什么是断言?

2.2、GateWay过滤器

2.3、过滤器执行顺序

2.4、使用GatewayFilter进行ip拦截

2.5、使用Gateway做token校验

2.6、使用GateWay实现限流

2.7、GateWay的跨域配置


1、什么是网关

        网关是微服务最边缘的服务 直接暴露给用户,用来做用户和微服务的桥梁。
        没有网关:客户端直接访问我们的微服务,会需要在客户端配置很多的 ip port ,如果user-service 并发比较大,则无法完成负载均衡。
        
        有网关:客户端访问网关,网关来访问微服务,(网关可以和注册中心整合,通过服务名称找到目标的 ip prot )这样只需要使用 服务名称即可访问微服务 ,可以实现 负载均衡,可 以实现 token 拦截,权限验证,限流等操作 。

        网关作为系统的唯一流量入口,封装内部系统的架构,所有请求都先经过网关,由网关将请求路由到合适的微服务,所以,使用网关的好处在于:

    (1)简化客户端的工作。网关将微服务封装起来后,客户端只需同网关交互,而不必调用各个不同服务;
    (2)降低函数间的耦合度。 一旦服务接口修改,只需修改网关的路由策略,不必修改每个调用该函数的客户端,从而减少了程序间的耦合性
    (3)解放开发人员把精力专注于业务逻辑的实现。由网关统一实现服务路由(灰度与ABTest)、负载均衡、访问控制、流控熔断降级等非业务相关功能,而不需要每个服务 API 实现时都去考虑

Nginx 和 Gateway 的区别:

        Nginx 是服务器级别的,将请求转发到gateway(负载均衡)

        Nginx 是用户到前端工程的网关,对外网关

        gateway是项目级别的,进行路由转发

        Gateway是微服务网关,是前端工程到后台服务之间的一个对内网关

2、断言和GateWay过滤器

网关请求流图:

2.1、什么是断言?

        通俗的说,断言就是一些布尔表达式 ,满足条件的返回 true ,不满足的返回 false
        Spring Cloud Gateway 将路由作为 Spring WebFlux HandlerMapping 基础架构的一部分 进行匹配。Spring Cloud Gateway 包括许多内置的路由断言工厂。所有这些断言都与 HTTP 请求的不同属性匹配。您可以将 多个路由断言可以组合 使用。
网关路由可以配置的内容包括:
        路由id:路由唯一标示
        uri:路由目的地,支持lb和http两种
        predicates:路由断言,判断请求是否符合要求,符合则转发到路由目的地
        filters: 路由过滤器 ,处理请求或响应

         表示如果访问/doLogin就会转发到/login-service上;-After代表必须在2022-03-22 9:42:59 以后才能进行转发,在此之前访问/doLogin是不会进行转发的;Method代表该请求必须是GET或者Post请求才可以。三者都满足时才能进行访问。

Spring提供了11种基本的Predicate工厂:

2.2、GateWay过滤器

        gateway 里面的过滤器和 Servlet 里面的过滤器,功能差不多,路由过滤器可以用于修改进入

Http 请求和返回 Http 响应 。
过滤器分类:

Gateway网关的过滤器分为两种,一种是局部过滤器,一种是全局过滤器
过滤器,顾名思义,就是过滤一些请求,在这里,局部过滤器需要配置某个路由,才能过滤(可以给某个路径单独做处理)。全局过滤器的作用是处理一切进入网关的请求和微服务响应,与GatewayFilter的作用一样

  • GatewayFilter:应用到单个路由或者一个分组的路由上。
  • GlobalFilter:应用到所有的路由上。

2.3、过滤器执行顺序

每个过滤器都会被执行两次,过滤分为pre和post。

pre:请求前调用。
post:响应结果返回时调用,顺序和pre完全相反。

请求进入网关会碰到三类过滤器:

路由的过滤器:是针对特定路由的过滤器

DefaultFilter:DefaultFilter(默认过滤器)是预定义的全局过滤器,提供了一些常用功能的实

GlobalFilter:是应用于所有路由的过滤器。

spring:
  cloud:
    gateway:
      routes:
        - id: user-service 
        uri: lb://userservice 
        predicates: 
        - Path=/user/**
        filters: # 过滤器
        - AddRequestHeader=Truth, 路由过滤器,只针对当前路由生效 # 添加请求头
      default-filters: # 默认过滤项
      - AddRequestHeader=Truth, 默认过滤器,所有路由生效! 

请求路由后,会将当前路由过滤器和DefaultFilter、GlobalFilter,合并到一个过滤器链(集合)中,排序后依次执行每个过滤器:

排序规则如下:

每一个过滤器都必须指定一个int类型的order值,order值越小,优先级越高,执行顺序越靠前。
GlobalFilter通过实现Ordered接口,或者添加@Order注解来指定order值,由我们自己指定。路由过滤器和defaultFilter的order由Spring指定,默认是按照声明顺序从1递增。当过滤器的order值一样时,会按照 defaultFilter > 路由过滤器 > GlobalFilter的顺序执行。

2.4、使用GatewayFilter进行ip拦截

       前端发起请求---->过滤器拦截获取访问ip(request.getHeaders().gethost().getHostString())--->去数据库中查询黑名单的ip集合--->list.contions(ip)---->判断访问的ip是否为黑名单里的--->放行/拦截

       如果并发量大的情况,所有的请求都去数据库中查询黑名单,这样的话数据库的压力较大。可以把一些指定的黑名单ip直接写死,写为常量集合。这样可以先判断常量集合中是否存才,没有再去数据库中查询,这里也可以使用redis缓存黑名单ip来减轻数据库的压力。

2.5、使用Gateway做token校验

 使用GateWay做统一用户认证,使用的是jwt生成的token。用户发起登录请求到网关,请求头中携带token,网关的全局过滤器进行拦截,校验token。

/**
 *
 * 全局过滤器
 * @author :Rk.
 * @date : 2022/11/23
 */
@Component
@Slf4j
public class AuthGlobalFilter implements GlobalFilter, Ordered {


    private AntPathMatcher antPathMatcher = new AntPathMatcher();

    /**
     * 拦截请求 进行过滤
     * @param exchange
     * @param chain
     * @return
     */
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        String path = request.getURI().getPath();
        log.info("==="+path);

        //内部服务接口,不允许外部访问 如果是以下 直接拦截
        if(antPathMatcher.match("/**/inner/**", path)) {
            ServerHttpResponse response = exchange.getResponse();
            return out(response, ResultCodeEnum.PERMISSION);
        }

        Long userId = this.getUserId(request);
        //api接口,异步请求,校验用户必须登录
        if(antPathMatcher.match("/api/**/auth/**", path)) {
            //如果userid为空 则认证失败 说明用户未登录 进行拦截
            if(StringUtils.isEmpty(userId)) {
                ServerHttpResponse response = exchange.getResponse();
                return out(response, ResultCodeEnum.LOGIN_AUTH);
            }
        }
        //继续向下(优先级更低的过滤器)执行
        return chain.filter(exchange);

    }


    /**
     * 过滤器优先级 返回值越小,执行优先级越高
     * @return
     */
    @Override
    public int getOrder() {
        return 0;
    }


    /**
     * 接口鉴权失败返回数据
     * @param response
     * @param resultCodeEnum
     * @return
     */
    private Mono<Void> out(ServerHttpResponse response, ResultCodeEnum resultCodeEnum) {
        Result result = Result.build(null, resultCodeEnum);
        byte[] bits = JSONObject.toJSONString(result).getBytes(StandardCharsets.UTF_8);
        DataBuffer buffer = response.bufferFactory().wrap(bits);
        //指定编码,否则在浏览器中会中文乱码
        response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
        return response.writeWith(Mono.just(buffer));
    }

    /**
     * 获取当前登录用户id
     * @param request
     * @return
     */
    private Long getUserId(ServerHttpRequest request) {
        String token = "";
        //获取请求头中的token
        List<String> tokenList = request.getHeaders().get("token");
        if(null  != tokenList) {
            token = tokenList.get(0);
        }
        //如果token不为空
        if(!StringUtils.isEmpty(token)) {
            //校验token并获取UserId
            return JwtHelper.getUserId(token);
        }
        return null;
    }

}

2.6、使用GateWay实现限流

什么是限流?

通俗的说,限流就是 限制一段时间内,用户访问资源的次数 ,减轻服务器压力,限流大致分为两种:
        1. IP 限流(5s 内同一个 ip 访问超过 3 次,则限制不让访问,过一段时间才可继续访问)
        2. 请求量限流(只要在一段时间内(窗口期),请求次数达到阀值,就直接拒绝后面来的访问了, 过一段时间才可以继续访问)(粒度可以细化到一个 api(url),一个服务)

 限流模型:限流模型:漏斗算法 ,令牌桶算法,窗口滑动算法 计数器算法

入不敷出
        1)、所有的请求在处理之前都需要拿到一个可用的令牌才会被处理;
        2)、根据限流大小,设置按照一定的速率 往桶里添加令牌;
        3)、桶设置最大的放置令牌限制 ,当桶满时、新添加的令牌就被丢弃或者拒绝;
        4)、请求达到后首先要获取令牌桶中的令牌,拿着令牌才可以进行其他的业务逻辑,处理完
        业务逻辑之后,将令牌直接删除;
        5)、令牌桶有最低限额,当桶中的令牌达到最低限额的时候,请求处理完之后将不会删除令
        牌,以此保证足够的限流;
结合redis做限流:
        Spring Cloud Gateway 已经内置了一个 RequestRateLimiterGatewayFilterFactory,我们可以直接使用。目前 RequestRateLimiterGatewayFilterFactory 的实现依赖于 Redis,还要引入 spring-boot-starter-data-redis-reactive。这个只能对某一个路由做限流,需要对使用限流的路由做配置。

配置了 RequestRateLimiter 的限流过滤器,
该过滤器需要配置三个参数:
burstCapacity:令牌桶总容量。
replenishRate:令牌桶每秒填充平均速率。
key-resolver:用于限流的键的解析器的 Bean 对象的名字。它使用 SpEL 表达式根据#{@beanName}从 Spring 容器中获取 Bean 对象。
RequestRateLimiterConfig配置类:
/**
 * 自定义请求限制的
 */
@Configuration
public class RequestLimitConfig {

	//ip限流
    // 针对某一个接口 ip来限流  /doLogin    每一个ip 10s只能访问3次
    @Bean
    @Primary // 主候选的
    public KeyResolver ipKeyResolver() {
        return exchange -> Mono.just(exchange.getRequest().getHeaders().getHost().getHostString());
    }

	//把请求路径作为限流
    // 针对这个路径来限制  /doLogin
    // api 就是 接口  外面一般把gateway    api网关  新一代网关
    @Bean
    public KeyResolver apiKeyResolver() {
        return exchange -> Mono.just(exchange.getRequest().getPath().value());
    }

	/*** 用户 id 限流 
	* 把用户 ID 作为限流的 key 
	** @return */ 
	@Bean 
	public KeyResolver userKeyResolver() {
		return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("userId")); 
	}

}

下面是一个秒杀的案例:

(秒杀项目) 4.9 削峰限流与防刷(核心)_妙先森的博客-CSDN博客_削峰和限流

2.7、GateWay的跨域配置

跨域? ajax 同源策略:8080   8081
因为网关是微服务的边缘 所有的请求都要走网关 跨域的配置只需要写在网关即可.
方法一:配置类
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.reactive.CorsWebFilter;
import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource;
import org.springframework.web.util.pattern.PathPatternParser;

@Configuration
public class CorsConfig {


    @Bean
    public CorsWebFilter corsFilter() {
        CorsConfiguration config = new CorsConfiguration();
        config.addAllowedMethod("*");
        config.addAllowedOrigin("*");
        config.addAllowedHeader("*");

        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(new PathPatternParser());
        source.registerCorsConfiguration("/**", config);

        return new CorsWebFilter(source);
    }
}

方法二:配置文件

spring:
  cloud:
    gateway:
      globalcors:
        corsConfigurations:
          '[/**]'
            allowCredentials: true
            allowedOrigins: "*"
            allowedMethods: "*"
            allowedHeaders: "*"
spring:
  cloud:
    gateway:
      globalcors: # 全局的跨域处理
        add-to-simple-url-handler-mapping: true # 解决options请求被拦截问题
        corsConfigurations:
          '[/**]':
            allowedOrigins: # 允许哪些网站的跨域请求 
              - "http://localhost:8090"
            allowedMethods: # 允许的跨域ajax的请求方式
              - "GET"
              - "POST"
              - "DELETE"
              - "PUT"
              - "OPTIONS"
            allowedHeaders: "*" # 允许在请求中携带的头信息
            allowCredentials: true # 是否允许携带cookie
            maxAge: 360000 # 这次跨域检测的有效期

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Rk..

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值