93-Spring Cloud [Alibaba] 2021.0.4 JDK17之前的最新生产版(第8章:网关】路由器和过滤器:Gateway(组件4))

第8章:🚩【网关】路由器和过滤器:Gateway(组件4)

1 网关的作用:

反向代理路由微服务、鉴权、流量控制、熔断、日志监控等,比如返回token的时候,我们就可以在响应过滤的时候去做。

2 网关的位置:

3 网关的选择:

官方推荐使用新一代网关gateway,理由如下:
SpringCloud GetWay 是基于webFlux框架实现的,而WebFlux框架底层则使用了高性能的Reactor模式通信框架Netty。(异步非阻塞IO模型),扩展性也更强。
而Zuul使用的是(同步阻塞IO模型:一个请求会创建一个线程),吞吐量会低很多,不支持长连接。

4 名词解释

Predicate 断言
:这是一个 Java 8 函数Predicate。用来判断请求是否符合设定的规则。
Filter 过滤器
 :这些是使用特定工厂构建的 Spring FrameworkGatewayFilter实例。在这里可以在发送下游请求之前或之后修改请求和响应。
Route 路由
:它由 ID、目标 URI、断言集合和过滤器集合定义。如果 聚合断言为真,则匹配路由。

5 原理:过滤器链:

  1. 客户端向 Spring Cloud Gateway 发出请求。
  2. 如果网关处理程序映射确定请求与路由匹配,则将其发送到网关 Web 处理程序。
  3. 此处理程序通过特定于请求的过滤器链运行请求。
  4. 过滤器用虚线划分的原因是过滤器可以在发送代理请求之前和之后运行逻辑。
  5. 执行所有“预”过滤器逻辑。
  6. 然后发出代理请求。
  7. 发出代理请求后,将运行“发布”过滤器逻辑。

6 实操:搭建网关服务:

1 pom文件:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.lzket</groupId>
        <artifactId>cloud-study</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <artifactId>m30-gateway-9000</artifactId>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>
2 yml配置:
server:
  port: 9000 #
spring:
  cloud:
    gateway:
      routes:
        - id: order_gateway # # 配置的一个路由id,唯一就可以
          uri: http://localhost:8033 # 配置代理路由的路径
          predicates:
            - Path=/order/** # 请求路径如果按照/order/开头,就匹配
        - id: goods_gateway # # 配置的一个路由id,唯一就可以
          uri: http://localhost:8034 # 配置代理路由的路径
          predicates:
            - Path=/goods/** # 请求路径如果按照/goods/开头,就匹配
🚩查看类:GatewayAutoConfiguration
@Bean
public RouteLocator routeDefinitionRouteLocator(GatewayProperties properties, List<GatewayFilterFactory> gatewayFilters, List<RoutePredicateFactory> predicates, RouteDefinitionLocator routeDefinitionLocator, ConfigurationService configurationService) {
    return new RouteDefinitionRouteLocator(routeDefinitionLocator, predicates, gatewayFilters, properties, configurationService);
}
在这个类中会去定义【路由:断言+过滤器】
1 🚩断言工厂:默认的有这么多:
注意:每个断言工厂有名字 :名字就是RoutePredicateFactory前面那一段:
比如Path RoutePredicateFactory 的名字就是 Path
比如AfterRoutePredicateFactory的名字就是 After
...
yml中的配置格式就是:
predicates:
- 断言工厂名字= 或参数名称, 正则表达式
可以由下面的一个多多个断言组成,形成聚合断言来判断请求
spring:
  cloud:
    gateway:
      routes:
      - id: order_route  # 配置的一个id,唯一就可以
        uri: http://localhost:8033 # 配置代理路由的路径
        predicates:
        - Path=/order/**   # 根据路径是否匹配来生效
        - Cookie=mycookie,mycookievalue # 判断Cookie中是否又名字mycookie和值mycookievalue
        - After=2017-01-20T17:42:47.789-07:00[Asia/Shanghai] # 在某时间以后生效[时区]
        - Before=2017-01-20T17:42:47.789-07:00[America/Denver] # 在某时间以前生效
        - Between=2017-01-20T17:42:47.789-07:00[America/Denver], 2017-01-21T17:42:47.789-07:00[America/Denver] # 这段时间生效
        - Header=X-Request-Id, \d+ # 具有头信息,第二个是正则表达式
        - Host=**.lzket.com,**.lzket.com # 根据主机来判断
        - Method=GET,POST # 判断是不是GET或者POST方法
        - Query=red, gree. # 查询参数来匹配,red是等值,gree是正则前缀
        - RemoteAddr=192.168.1.1/24 # 可以根据ip来配置
还能通过权重来配置:Weight
spring:
  cloud:
    gateway:
      routes:
      - id: weight_high
        uri: https://weighthigh.org
        predicates:
        - Weight=group1, 8
      - id: weight_low
        uri: https://weightlow.org
        predicates:
        - Weight=group1, 2
2 🚩Gateway内置过滤器:太多了,这里举一个例子
过滤器的名称等于类名去掉GatewayFilterFactory
例如:AddRequestHeaderGatewayFilterFactory的名字:AddRequestHeader
再比如:AddRequestParameterGatewayFilterFactory的名字:AddRequestParameter
头信息的过滤器:
spring:
  cloud:
    gateway:
      routes:
      - id: add_request_header_route
        uri: https://example.org
        filters:
        - AddRequestHeader=X-Request-red, blue # 
将标头添加到所有匹配请求的下游请求标头中。
格式:
filters:
- 具体的过滤器名称=参数名称,参数值或正则表达式
例如:
server:
  port: 9000 #
spring:
  cloud:
    gateway:
      routes:
        - id: order_gateway # # 配置的一个路由id,唯一就可以
          uri: http://localhost:8033 # 配置代理路由的路径
          predicates:
            - Path=/order/** # 请求路径如果按照/order/开头,就匹配
        - id: goods_gateway # # 配置的一个路由id,唯一就可以
          uri: http://localhost:8034 # 配置代理路由的路径
          predicates:
            - Path=/goods/** # 请求路径如果按照/goods/开头,就匹配
          filters:
            - AddRequestParameter=goodsId, 333 # 添加请求参数
3 设置默认过滤器
要添加过滤器并将其应用于所有路由,您可以使用spring.cloud.gateway.default-filters.
此属性采用过滤器列表。以下清单定义了一组默认过滤器:
spring:
  cloud:
    gateway:
      default-filters:
      - AddResponseHeader=X-Response-Default-Red, Default-Blue
      - PrefixPath=/http

7🚩🚩全局过滤器

package com.lzket;

import org.reactivestreams.Publisher;
import org.reactivestreams.Subscriber;
import org.reactivestreams.Subscription;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.CoreSubscriber;
import reactor.core.publisher.Mono;

import java.nio.charset.Charset;
import java.util.List;

/**
 * @author:菩提老师
 * @学习地址:lzket.com
 */
@Configuration
public class config {
    @Bean
    public GlobalFilter customFilter() {
        return new CustomGlobalFilter();
    }
}

class CustomGlobalFilter implements GlobalFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        System.out.println("进入全局过滤器。。。");
        ServerHttpRequest request = exchange.getRequest();
        String goodsId = request.getQueryParams().getFirst("goodsId");
        if(goodsId==null){
            ServerHttpResponse response = exchange.getResponse();
            //设置响应头
            response.getHeaders().add("ContentType","application/json;charset=utf-8");
            //设置状态码
            response.setStatusCode(HttpStatus.BAD_REQUEST);
            // 封装响应数据
            String str = "不好意思,你的参数不存在!";
            DataBuffer dataBuffer = response.bufferFactory().wrap(str.getBytes(Charset.forName("GBK")));
            return response.writeWith(Mono.just(dataBuffer));

        }
        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {// 排序,数字越小,越先执行
        return 0;
    }
}

8 LoadBalancerClient过滤器 负载均衡过滤器:

上面的方式是uri写死的,不能实现负载均衡,我们需要按照微服务的名称实现负载均衡
pom文件加依赖:
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
server:
  port: 9000 #
spring:
  cloud:
    gateway:
      routes:
#        - id: order_gateway # # 配置的一个路由id,唯一就可以
#          uri: http://localhost:8033 # 配置代理路由的路径
#          predicates:
#            - Path=/order/** # 请求路径如果按照/order/开头,就匹配
#        - id: goods_gateway # # 配置的一个路由id,唯一就可以
#          uri: http://localhost:8034 # 配置代理路由的路径
#          predicates:
#            - Path=/goods/** # 请求路径如果按照/goods/开头,就匹配
#          filters:
#            - AddRequestParameter=goodsId, 333 # 添加请求参数
        - id: order_gateway
          uri: lb://order-nacos-loadbalancer #  负载均衡写法
          predicates:
            - Path=/order/**
        - id: goods_gateway
          uri: http://goods-nacos-loadbalancer #  负载均衡写法
          predicates:
            - Path=/goods/**
          filters:
            - AddRequestParameter=goodsId, 999
    nacos:
      discovery:
        server-addr: 192.168.124.10:8848 #配置Nacos地址
        username: nacos # 默认的用户名和密码,可以到nacos控制台进行更改
        password: nacos # 默认的用户名和密码,可以到nacos控制台进行更改
    loadbalancer:
      nacos:
        enabled: true # 开启nacos的负载均衡随机权重算法

9 流畅的 Java 路由 API 配置(代码配置):🚩

package com.lzket;

import org.reactivestreams.Publisher;
import org.reactivestreams.Subscriber;
import org.reactivestreams.Subscription;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.cloud.gateway.filter.factory.AddRequestParameterGatewayFilterFactory;
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;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.CoreSubscriber;
import reactor.core.publisher.Mono;

import java.nio.charset.Charset;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @author:菩提老师
 * @学习地址:lzket.com
 */
@Configuration
public class config {
    @Bean
    public GlobalFilter customFilter() {
        return new CustomGlobalFilter();
    }

    // static imports from GatewayFilters and RoutePredicates
    @Bean
    public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
        RouteLocatorBuilder.Builder routes = builder.routes();
        // 代替yml配置
        return routes
                .route("user", r -> r.path("/user/**").uri("lb://user-nacos-loadbalancer"))
                .route("goods", r -> r.path("/goods/**").uri("lb://goods-nacos-loadbalancer"))
                .route("order", r -> r.path("/order/**").uri("lb://order-nacos-loadbalancer"))
                .build();

        // 在这里可以配置路由的各种断言 和多个路由

//        return builder.routes()
//                .route(r -> r.host("lzket.com").and()
//                        .path("/user/**")
//                        .filters(f -> f.addResponseHeader("X-TestHeader", "foobar"))
//                        .uri("http://lzket.com/user")
//                )
//                .route(r -> r.order(-1)
//                        .path("/goods/**")
                                .and()
                        .after().and()
                        .before().and()
                        .between().and()
                        .cookie().and()
                        .weight().and()
                        .method()
//                        .filters(f -> f.addRequestParameter("goodsId","999"))
//                        .uri("http://httpbin.org:80")
//                )
//                .build();
    }

}

class CustomGlobalFilter implements GlobalFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        System.out.println("进入全局过滤器。。。");
        ServerHttpRequest request = exchange.getRequest();
        String goodsId = request.getQueryParams().getFirst("goodsId");
//        if(goodsId==null){
//            ServerHttpResponse response = exchange.getResponse();
//            //设置响应头
//            response.getHeaders().add("ContentType","application/json;charset=utf-8");
//            //设置状态码
//            response.setStatusCode(HttpStatus.BAD_REQUEST);
//            // 封装响应数据
//            String str = "不好意思,你的参数不存在!";
//            DataBuffer dataBuffer = response.bufferFactory().wrap(str.getBytes(Charset.forName("GBK")));
//            return response.writeWith(Mono.just(dataBuffer));
//
//        }
        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {// 排序,数字越小,越先执行
        return 0;
    }
}

10 全局超时配置

spring:
  cloud:
    gateway:
      httpclient:
        connect-timeout: 1000 # 设置全局的连接超时时间
        response-timeout: 5s # 设置全局的服务响应时间
注意:如果是nacos的话,gateway需要引入负载均衡组件,不然会报错503,因为网关默认的负载均衡的生命周期是【可选】: true
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-loadbalancer</artifactId>
</dependency>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

菩提老师

如果帮到了您,感谢您的鼓励

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

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

打赏作者

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

抵扣说明:

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

余额充值