微服务のGeteWay

目录

概念:

三大核心:

工作流程:

9527网关如何做路由映射:

GetWay高级特性:

按服务名动态路由服务:

[断言Route Predicate Factories :](#断言Route Predicate Factories :)

获取当前时区时间:

[After Route :](#After Route :)

例:

[Before,Between 同理:](#Before,Between 同理:)

[Cookie Route :](#Cookie Route :)

[Header Route :](#Header Route :)

[自定义断言 :](#自定义断言 :)

Filter过滤器:

[1. Filter的作用](#1. Filter的作用)

[2. Filter的分类](#2. Filter的分类)

[1. Pre Filter(前置过滤器)](#1. Pre Filter(前置过滤器))

[2. Post Filter(后置过滤器)](#2. Post Filter(后置过滤器))

[3. Error Filter(错误过滤器)](#3. Error Filter(错误过滤器))

[请求头AddRequestHeader :](#请求头AddRequestHeader :)

[请求参数 RemoveRequestParameter和AddRequestParameter](#请求参数 RemoveRequestParameter和AddRequestParameter)

请求回应ResponseHeader:

前缀和路径相关组:

全局过滤器:

自定义条件Filter:


概念:

微服务中网关在哪里?

三大核心:

Route路由 ,Predicate断言,Filter过滤器

工作流程:

核心逻辑:路由转发,断言判断,执行过滤器链

9527网关如何做路由映射:

前提:

我们需要提前把GeteWay服务注册到consul当中

核心:配置yml

复制代码
server:
  port: 9527

spring:
  application:
    name: cloud-gateway #以微服务注册进consul或nacos服务列表内
  cloud:
    consul: #配置consul地址
      host: localhost
      port: 8500
      discovery:
        prefer-ip-address: true
        service-name: ${spring.application.name}

    gateway:
      routes:
        - id: pay_routh1 #pay_routh1                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名
          uri: http://localhost:8001                #匹配后提供服务的路由地址
          predicates:
            - Path=/pay/gateway/get/**              # 断言,路径相匹配的进行路由


        - id: pay_routh2 #pay_routh2                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名
          uri: http://localhost:8001                #匹配后提供服务的路由地址
          predicates:
            - Path=/pay/gateway/info/**              # 断言,路径相匹配的进行路由

隐真示假 ,让用户不知道我们真正的地址:

没有使用GeteWay之前访问的路径是 http://localhost:8001/pay/gateway/get/1

使用了GeteWay之后可以使用http://localhost:9527/pay/gateway/get/1

将feignclient请求的微服务更改为注册中心的geteway:

先启动 8001微服务和feign80,可以看到请求失败:

启动9527网关后,请求成功,说明现在请求微服务必须通过geteway,配置成功:

GetWay高级特性:

按服务名动态路由服务:

格式:

uri:lb://service

微服务名为cloud-payment-service,通过使用注册中心的微服务名称,就可以动态的配置路由地址,配置如下:

断言Route Predicate Factories :

官网地址:点击跳转

通过断言判断请求是否路由到微服务。

获取当前时区时间:

在讲解之前,我们需要先知道如何获取默认时区时间

复制代码
public static void main(String[] args)
{
    ZonedDateTime zbj = ZonedDateTime.now(); // 默认时区
    System.out.println(zbj);
}

After Route :

官网描述如下:

表示只有在当前时间之后,该路由才会被匹配。

例:

yml配置格式 ,我配置的时间是大于当前时间的,但我们必须要在该时间后才能访问到:

spring:

cloud:

gateway:

routes:

  • id: route1

uri: http://localhost:8081

predicates:

  • Path=/api/**

  • After=2024-12-26T17:31:14.523838700+08:00[Asia/Shanghai]

访问结果如下:

Before,Between 同理:

官方描述如下:

通过键值对的方式配置Cookie,访问时必须带上Cookie,否则访问不到服务。

Header Route :

请求头要有X-Request-Id属性并且值为整数的正则表达式

其他的断言用到了请查阅官方文档,写得很详细

自定义断言 :

java 复制代码
@Component
public class MyRoutePredicateFactory extends AbstractRoutePredicateFactory<MyRoutePredicateFactory.Config>
{
    public MyRoutePredicateFactory()
    {
        super(MyRoutePredicateFactory.Config.class);
    }

    @Validated
    public static class Config{
        @Setter
        @Getter
        @NotEmpty
        private String userType; //钻、金、银等用户等级
    }

    @Override
    public Predicate<ServerWebExchange> apply(MyRoutePredicateFactory.Config config)
    {
        return new Predicate<ServerWebExchange>()
        {
            @Override
            public boolean test(ServerWebExchange serverWebExchange)
            {
                //检查request的参数里面,userType是否为指定的值,符合配置就通过
                String userType = serverWebExchange.getRequest().getQueryParams().getFirst("userType");

                if (userType == null) return false;

                //如果说参数存在,就和config的数据进行比较
                if(userType.equals(config.getUserType())) {
                    return true;
                }

                return false;
            }
        };
    }

    //开启shortcut支持
    @Override
    public List<String> shortcutFieldOrder() {
        return Collections.singletonList("userType");
    }
}

YML配置:

必须加上usertype=diamond才能访问的服务

Filter过滤器:

官方文档:点击跳转

1. Filter的作用

Filters 通常用于以下几种场景:

  • 请求预处理:对请求进行检查、修改、验证或转换,如请求数据格式化、认证、限流、日志记录等。
  • 响应后处理:在响应数据返回客户端之前进行处理,如数据加密、响应格式化、缓存处理等。
  • 路由转发:基于请求中的一些特定信息(如URL路径、请求头、请求参数等)决定如何路由请求。

2. Filter的分类

在不同的网关架构中,Filter的分类有所不同。以 Spring Cloud GatewayAPI Gateway 为例,它们通常将 Filter 分为以下几种类型:

1. Pre Filter(前置过滤器)

前置过滤器在请求到达服务之前执行。它们可以用来进行:

  • 身份验证:如检查JWT令牌是否合法。
  • 日志记录:记录请求的信息。
  • 限流:检查请求是否超过某些限制。
2. Post Filter(后置过滤器)

后置过滤器在服务响应后,客户端接收到响应之前执行。它们可以用来:

  • 修改响应:比如修改响应体或响应头。
  • 性能监控:计算请求处理时间,进行性能分析。
  • 缓存处理:根据某些条件返回缓存的响应。
3. Error Filter(错误过滤器)

错误过滤器用于处理请求过程中发生的错误。例如:

  • 统一错误处理:当发生异常时,返回特定的错误响应。
  • 日志记录:记录错误信息以便后续分析。

请求头AddRequestHeader :

是 Spring Cloud Gateway 中的一个 GatewayFilter 工厂,用于在请求转发之前,向请求中添加自定义的 HTTP 请求头。

向服务端新增方法:

java 复制代码
@GetMapping(value = "/pay/gateway/filter")
    public ResultData<String> getGatewayFilter(HttpServletRequest request)
    {
        String result = "";
        Enumeration<String> headers = request.getHeaderNames();
        while(headers.hasMoreElements())
        {
            String headName = headers.nextElement();
            String headValue = request.getHeader(headName);
            System.out.println("请求头名: " + headName +"\t\t\t"+"请求头值: " + headValue);
            if(headName.equalsIgnoreCase("X-Request-atguigu1")
                    || headName.equalsIgnoreCase("X-Request-atguigu2")) {
                result = result+headName + "\t " + headValue +" ";
            }
        }
        return ResultData.success("getGatewayFilter 过滤器 test: "+result+" \t "+ DateUtil.now());
    }

yml配置:

复制代码
- id: pay_routh3 #pay_routh3
  uri: lb://cloud-payment-service                #匹配后提供服务的路由地址
  predicates:
    - Path=/pay/gateway/filter/**              # 断言,路径相匹配的进行路由
  filters:
    - AddRequestHeader=X-Request-atguigu1,atguiguValue1  # 请求头kv,若一头含有多参则重写一行设置
    - AddRequestHeader=X-Request-atguigu2,atguiguValue2

运行结果:

请求参数 RemoveRequestParameter和AddRequestParameter

打印输入的参数

java 复制代码
System.out.println("=============================================");
        String customerId = request.getParameter("customerId");
        System.out.println("request Parameter customerId: "+customerId);

        String customerName = request.getParameter("customerName");
        System.out.println("request Parameter customerName: "+customerName);
        System.out.println("=============================================");

yml添加:

复制代码
- AddRequestParameter=customerId,9527001 # 新增请求参数Parameter:k ,v
- RemoveRequestParameter=customerName   # 删除url请求参数customerName,你传递过来也是null

测试请求的路径;

http://localhost:9527/pay/gateway/filter?customerId=9999&customerName=z3

打印结果:

可以发现添加到参数会覆盖原有的值,移除的参数就算是传值也会被置为null

请求回应ResponseHeader:

修改之前的响应头:

配置yml:

复制代码
- AddResponseHeader=X-Response-atguigu, BlueResponse # 新增请求参数X-Response-atguigu并设值为BlueResponse
- SetResponseHeader=Date,2099-11-11 # 设置回应头Date值为2099-11-11
- RemoveResponseHeader=Content-Type # 将默认自带Content-Type回应属性删除

修改后响应头:

前缀和路径相关组:

The PrefixPath GatewayFilter Factory

The SetPath GatewayFilter Factory

The RedirectTo GatewayFilter Factory

全局过滤器:

官方文档:点击跳转

新建global类:

java 复制代码
package com.atguigu.cloud.mygateway;

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.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.Map;

@Component
@Slf4j
public class MyGlobalFilter implements GlobalFilter, Ordered {

    public final static String BEGIN_VISIT_TIME = "beginVisitTime";

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //记录访问接口开始时间
        exchange.getAttributes().put(BEGIN_VISIT_TIME, System.currentTimeMillis());
        //返回统计的各个结果给后台
        return chain.filter(exchange).then(Mono.fromRunnable(()->{
            Long beginVisitTime = exchange.getAttribute(BEGIN_VISIT_TIME);
            if(beginVisitTime != null){
                log.info("访问接口主机:"+exchange.getRequest().getURI().getHost());
                log.info("访问接口端口:"+exchange.getRequest().getURI().getPort());
                log.info("访问接口URL:"+exchange.getRequest().getURI().getPath());
                log.info("访问接口URL后面的参数:"+exchange.getRequest().getURI().getRawQuery());
                log.info("访问接口时长:"+(System.currentTimeMillis()-beginVisitTime)+"毫秒");
                log.info("=================分割线======================");
                System.out.println();
            }
        }));
    }

    @Override
    public int getOrder() {
        return 0;
    }
}

yml:

测试结果:

自定义条件Filter:

过滤条件是 必须带有 'yuanshen'的请求参数

java 复制代码
package com.atguigu.cloud.mygateway;

import lombok.Getter;
import lombok.Setter;
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.cloud.gateway.filter.factory.SetPathGatewayFilterFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
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
public class MyGatewayFilterFactory extends AbstractGatewayFilterFactory<MyGatewayFilterFactory.Config>
{
    public MyGatewayFilterFactory()
    {
        super(MyGatewayFilterFactory.Config.class);
    }


    @Override
    public GatewayFilter apply(MyGatewayFilterFactory.Config config)
    {
        return new GatewayFilter()
        {
            @Override
            public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain)
            {
                ServerHttpRequest request = exchange.getRequest();
                System.out.println("进入了自定义网关过滤器MyGatewayFilterFactory,status:"+config.getStatus());
                if(request.getQueryParams().containsKey("atguigu")){
                    return chain.filter(exchange);
                }else{
                    exchange.getResponse().setStatusCode(HttpStatus.BAD_REQUEST);
                    return exchange.getResponse().setComplete();
                }
            }
        };
    }

    @Override
    public List<String> shortcutFieldOrder() {
        return Arrays.asList("status");
    }

    public static class Config
    {
        @Getter@Setter
        private String status;//设定一个状态值/标志位,它等于多少,匹配和才可以访问
    }
}
//单一内置过滤器GatewayFilter

yml:

补充:

对应关系:

相关推荐
一弓虽8 分钟前
java基础学习——java集合简单介绍及使用
java·学习
Alan CGH11 分钟前
高并发写利器-组提交,我的Spring组件实战
java·后端·spring
苹果酱056729 分钟前
Pytorch机器学习——1 深度学习介绍
java·vue.js·spring boot·mysql·课程设计
喻师傅32 分钟前
SQL—替换字符串—replace函数用法详解
android·数据库·sql
Wind哥33 分钟前
VS2022引入sqlite数据库交互
数据库·c++·sqlite
马丁•路德•王37 分钟前
Java测试开发平台搭建(八) Jenkins
java·servlet·jenkins
童安格粉丝43 分钟前
linux下安装达梦数据库v8详解
linux·数据库·centos·达梦·安装·客户端·v8
李歘歘44 分钟前
Redis数据库——Redis雪崩、穿透、击穿
java·数据库·redis·mysql·缓存·go
我是鸹貔1 小时前
微服务-Eureka
微服务·eureka·架构