GateWay网关

一.为什么需要网关

网关是微服务架构中的统一入口组件,解决了分布式系统中的核心痛点:

二.搭建网关服务的步骤:

1.创建新的module,引入SpringCloudGateway的依赖和nacos的服务发现依赖:

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    <version>2023.0.1.2</version>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
    <version>4.1.4</version>
</dependency>

启动类上加上@EnableDiscoveryClient

  • 服务注册:让当前微服务自动向注册中心(如 Eureka、Nacos、Consul 等 )注册自身实例信息(IP、端口、服务名等 )。
  • 服务发现:使微服务能从注册中心查询其他服务的实例信息,结合 @LoadBalanced 等可实现基于服务名的调用、负载均衡。

2.编写路由配置及nacos地址

配置文件规范(推荐单文件 + Profile 分离),application.yml和application-route.yml

application.yml

spring:
  profiles:
    include: route  # 引入名为"route"的配置文件(用于分离路由配置,提升可读性)
  application:
    name: gateway  # 应用名称,在服务发现中心显示为"gateway"
  cloud:
    nacos:
      discovery:
        server-addr: http://192.168.88.1:8848  # Nacos服务发现地址,用于注册网关自身及发现其他微服务
server:
  port: 80  # 网关服务端口,通过80端口对外提供服务

其他微服务的配置进行服务注册

启动后nacos中会生成两个服务

配置路由规则application-route.yml(路由配置示例)

spring:
  cloud:
    gateway:
      routes:
        - id: itxb-route          # 路由唯一标识,建议使用有业务含义的名称(命名随意)
          uri: lb://itxb           # 负载均衡到名为"itxb"的微服务(通过服务发现中心获取实例地址---nacos中的服务名)

3.lb是负载均衡需要加上依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-loadbalancer</artifactId>
    <version>4.1.3</version>
</dependency>

4.GateWay网关的工作流程架构图

三.路由断言工厂Route Predicate Factory

1.什么是断言工厂

  • 谓词工厂:将配置文件中的字符串规则转换为路由匹配条件,本质是实现了RoutePredicateFactory接口的组件。
  • 示例Path=/api/itxb/**PathRoutePredicateFactory处理,判断请求路径是否匹配。

2. 短写法与长写法对比

类型配置示例(匹配请求参数 q=haha)对应工厂类
短写法- Query=q,hahaQueryRoutePredicateFactory
长写法

- name: Query

 args:

  param: q 

  regexp: haha

QueryRoutePredicateFactory

3.自定义断言(自定义一个以 VIP 断言工厂为例)

首先创建一个类VipRoutePredicateFactory(用于根据请求头参数判断是否为VIP请求)

/**
 * VIP路由谓词工厂 - 用于根据请求头参数判断是否为VIP请求
 * 示例配置:- Vip=user,VIP123
 */
@Component
public  class VipRoutePredicateFactory extends AbstractRoutePredicateFactory<VipRoutePredicateFactory.Config> {
    /**
     * 定义快捷写法的参数顺序--短写法
     * 如:- Vip=param,value
     */
    @Override
   public List<String> shortcutFieldOrder() {
        return Arrays.asList("param", "value");
    }
    /**
     * 应用谓词逻辑:判断请求头参数是否匹配
     * @param config 配置参数(包含要检查的请求头参数名和目标值)
     * @return 谓词函数,返回true时路由生效
     */
    @Override
    public Predicate<ServerWebExchange> apply(Config config) {
        return new GatewayPredicate() {
            @Override
            public boolean test(ServerWebExchange exchange) {
                //从请求头中获取参数
                String param = exchange.getRequest().getHeaders().getFirst(config.getParam());
                //判断参数是否匹配
                return param != null && param.equals(config.getValue());
            }
        };
    }

    /**
     * 配置参数类 - 定义可配置的属性
     * 需通过@Validated进行参数校验
     */
    @Validated   //会触发 Spring 对该类中的字段校验注解(如 @NotEmpty、@NotNull
    public static class Config {
        @NotEmpty
        private String  param;
       @NotEmpty
        private String  value;

        public String getParam() {
            return param;
        }

        public void setParam(String param) {
            this.param = param;
        }

        public String getValue() {
            return value;
        }

        public void setValue(String value) {
            this.value = value;
        }
    }
    public VipRoutePredicateFactory() {
        super(Config.class);
    }
}

配置路由规则使用

 正确访问

现在user=zhangsan

四.过滤器工厂

这是 Spring Cloud Gateway 过滤器(Filter) 的配置与执行流程说明图

1. 过滤器分类与对比

类型定义方式作用范围典型场景
路由过滤器配置文件定义仅当前路由生效路径重写、请求头修改
全局过滤器代码实现(接口)所有路由生效权限校验、响应时间记录

2.过滤器的作用:

(1).对路由的请求或响应做加工处理,比如添加请求头配置

(2).在路由下的过滤器只对当前路由的请求生效

现在重写路径请求(前端如果过来的是/api/itxb/ab->后端需要有这个路径,现在加上过去只需要/itxb/ab)

Spring提供了多种不同的路由过滤器工厂

过滤器工厂作用参数
AddRequestHeader为原始请求添加HeaderHeader的名称及值
AddRequestParameter为原始请求添加请求参数参数名称及值
AddResponseHeader为原始响应添加HeaderHeader的名称及值
DedupeResponseHeader剔除响应头中重复的值需要去重的Header名称及去重策略
Hystrix为路由引入Hystrix的断路器保护HystrixCommand的名称
FallbackHeaders为fallbackUri的请求头中添加具体的异常信息Header的名称
PrefixPath为原始请求路径添加前缀前缀路径
PreserveHostHeader为请求添加一个preserveHostHeader=true的属性,路由过滤器会检查该属性以决定是否要发送原始的Host
RequestRateLimiter用于对请求限流,限流算法为令牌桶keyResolver、rateLimiter、statusCode、denyEmptyKey、emptyKeyStatus
RedirectTo将原始请求重定向到指定的URLhttp状态码及重定向的url
RemoveHopByHopHeadersFilter为原始请求删除IETF组织规定的一系列Header默认就会启用,可以通过配置指定仅删除哪些Header
RemoveRequestHeader为原始请求删除某个HeaderHeader名称
RemoveResponseHeader为原始响应删除某个HeaderHeader名称
RewritePath重写原始的请求路径原始路径正则表达式以及重写后路径的正则表达式
RewriteResponseHeader重写原始响应中的某个HeaderHeader名称,值的正则表达式,重写后的值
SaveSession在转发请求之前,强制执行WebSession::save操作
secureHeaders为原始响应添加一系列起安全作用的响应头无,支持修改这些安全响应头的值
SetPath修改原始的请求路径修改后的路径
SetResponseHeader修改原始响应中某个Header的值Header名称,修改后的值
SetStatus修改原始响应的状态码HTTP 状态码,可以是数字,也可以是字符串
StripPrefix用于截断原始请求的路径使用数字表示要截断的路径的数量
Retry针对不同的响应进行重试retries、statuses、methods、series
RequestSize设置允许接收最大请求包的大小。如果请求包大小超过设置的值,则返回 413 Payload Too Large请求包大小,单位为字节,默认值为5M
ModifyRequestBody在转发请求之前修改原始请求体内容修改后的请求体内容
ModifyResponseBody修改原始响应体的内容修改后的响应体内容
Default为所有路由添加过滤器过滤器工厂名称及值

3.默认过滤器 

4.全局过滤器:

 全局过滤器的作用也是处理一来和微服务响应与GatewayFilter的作用一样。龙川评入以X天R区别在于GatewayFilter通过配置定义,处理逻辑是固定的。而GlobalFilter的逻辑需要自己写代码实现定义方式是实现GlobalFilter接口。

全局过滤器示例(响应时间记录)


/**
 * 全局过滤器,用于记录请求的执行时间
 * 实现了GlobalFilter接口,会对所有经过网关的请求生效
 * 实现了Ordered接口,用于指定过滤器的执行顺序
 */
@Component
@Slf4j
public class RtGlobalFilter implements GlobalFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        /**
         * 过滤器核心方法,处理请求和响应
         * @param exchange 服务器Web交换对象,包含请求和响应
         * @param chain 过滤器链,用于调用下一个过滤器
         * @return 响应完成的Mono对象
         */
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();
       String url= request.getURI().toString();
       long startTime = System.currentTimeMillis();
        log.info("请求{}开始:时间{}",url,startTime);
        /**
         * 记录请求开始时间
         * 调用过滤器链,处理请求
         * 使用doFinally方法,在请求完成后记录请求结束时间
         **/
        Mono<Void>filter=chain.filter(exchange).
                doFinally(signalType -> {
                    long endTime = System.currentTimeMillis();
                    log.info("请求{}结束:时间{}",url,endTime);
                    log.info("请求{}耗时:{}ms",url,endTime-startTime);
                });

        return filter;
    }
    /**
     * 获取过滤器的执行顺序
     * 值越小,优先级越高
     * @return 执行顺序值,这里设置为0
     */
    @Override
    public int getOrder() {
        return 0;
    }
}

请求后控制台打印

5.自定义过滤器工厂(一次性令牌生成)



/**
 * 一次性令牌网关过滤器工厂
 * 用于在每个响应中添加一个一次性令牌,可以是UUID或其他自定义格式
 * 继承自AbstractNameValueGatewayFilterFactory,支持配置令牌的名称和值类型
 */
@Slf4j
@Component
public class OnceTokenGatewayFilterFactory extends AbstractNameValueGatewayFilterFactory {
  public OnceTokenGatewayFilterFactory() {
      log.info("OnceTokenFilterFactory initialized");
  }
    /**
     * 应用过滤器配置并创建实际的过滤器实例
     * @param config 包含令牌名称和值类型的配置
     * @return 配置好的网关过滤器
     */
    @Override
    public GatewayFilter apply(NameValueConfig config) {
        return new GatewayFilter() {

            /**
             * 过滤器的核心处理逻辑
             * 在响应返回前添加一次性令牌到响应头中
             * @param exchange 服务器Web交换对象,包含请求和响应
             * @param chain 过滤器链,用于调用下一个过滤器
             * @return 响应完成的Mono对象
             */
            @Override
            public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
                // 在响应处理完成后执行令牌添加逻辑
                return chain.filter(exchange).then(Mono.fromRunnable(() -> {
                    // 获取响应对象和响应头
                    ServerHttpResponse response = exchange.getResponse();
                    HttpHeaders headers = response.getHeaders();

                    // 获取配置的值类型
                    String value = config.getValue();

                    // 如果配置的值类型为"uuid",则生成一个UUID作为令牌值
                    if ("uuid".equalsIgnoreCase(value)) {
                        value = UUID.randomUUID().toString();
                    }

                    // 将生成的令牌添加到响应头中
                    headers.add(config.getName(), value);
                }));
            }
        };
    }
}

路由配置并且使用

全局过滤器和GatewayFilter一样都可以对进入网关的请求和微服务的响应做加工处理 GatewayFilter网关过滤器:通过配置文件定义所以处理的逻辑是固定的且只有默认过滤器对所有路由请求生效

GLobalFilter全局过滤器:可以编写代码做自己的业务逻辑,如 登录状态判断,权限校验,请求限流 等,对所有的路由请求都生效

五.过滤器链的执行顺序

过滤器执行顺序

   每个过滤器都要设置一个 int 类型的 order 值,order 值越小,优先级越高,执行越靠前

  • GlobalFilter:需通过实现 Ordered 接口,或添加 @Order 注解来指定 order 值,由开发者自定义。
  • 路由过滤器、defaultFilterorder 由 Spring 管控,默认按声明顺序从 1 开始递增。

若多个过滤器 order 值相同,执行顺序为:defaultFilter → 路由过滤器 → GlobalFilter 。

六.网关的cors跨域配置  

1.跨域:域名不一致就是跨域,主要包括:
域名不同:www.taobao.com和www.taobao.org和 www,jd.com 和 miaosha.jd.com域名相同,

端口不同:localhost:8080和localhost8081

跨域问题:浏览器禁止请求的发起者与服务端发生跨域ajax请求,请求被浏览器拦截,导致前端无法正常调用后端接口

传统的解决方案:在每个 Controller 上添加 @CrossOrigin 注解,需逐个配置,Controller 数量多时代码冗余、维护复杂

解决方案:CORS

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值