Skip to content
章节导航

动态网关

基于 nacos 动态网关

pom 依赖

xml
<dependencies>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
    </dependency>

    <dependency>
        <groupId>com.github.itdachen.framework</groupId>
        <artifactId>fly-runner</artifactId>
    </dependency>

    <!-- 网关 -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-gateway</artifactId>
    </dependency>

    <!-- 动态网关 -->
    <dependency>
        <groupId>com.github.itdachen.framework.cloud</groupId>
        <artifactId>fly-cloud-gateway-dynamic-routes</artifactId>
    </dependency>

    <!-- openfeign 封装, RestTemplate 封装 -->
    <dependency>
        <groupId>com.github.itdachen.framework.cloud</groupId>
        <artifactId>fly-cloud-openfeign</artifactId>
    </dependency>

    <!-- 服务注册与发现 -->
    <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-bootstrap</artifactId>
    </dependency>

    <!-- 健康检查 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>

</dependencies>

配置文件

编写配置文件 'bootstrap.yml'

yaml
spring:
  profiles:
    active: dev

# 暴露 SpringBoot Actuator Endpoint
management:
  endpoints:
    web:
      exposure:
        include: '*'  # 需要开放的端点。默认值只打开 health 和 info 两个端点。通过设置 *, 可以开放所有端点
  endpoint:
    health:
      show-details: ALWAYS

编写配置文件 'bootstrap-dev.yml'

yaml
# 端口配置
server:
  port: 8080
  servlet:
    context-path: /api

# 认证中心配置
fly:
  cloud:
    auth:
      token:
        type: RSA
      app:
        service-id: auth
        app-id: ${spring.application.name}
        app-secret: 123456
    ## 网关配置
    gateway:
      ### 动态获取 nacos 中的路由配置
      routes:
        username: nacos
        password: nacos
        serverAddr: 127.0.0.1:8848
        namespace: b6783835-a27f-4ec3-b9ee-05bfa917e812
        dataId: GATEWAY_ROUTES
        group: GATEWAY_ROUTES
      ### 配置网关不拦截路径前缀, 不需要权限认证等
      ignore:
        matchers:
          - /auth/oauth/access_token
          - /auth/oauth/token
          - /api/actuator
          - /actuator
          - /admin/open/dict
          - /oss
          - /oss/upload
          - /flexible/login
          - /flexible/authentication/form


spring:
  application:
    name: gateway
  main:
    allow-circular-references: true
    allow-bean-definition-overriding: true
    web-application-type: REACTIVE

  servlet:
    # 文件上传
    multipart:
      max-file-size: 1024MB
      max-request-size: 1024MB

  cloud:
    nacos:
      username: nacos
      password: nacos
      server-addr: 127.0.0.1:8848
      discovery:
        enabled: true # 如果不想使用 Nacos 进行服务注册和发现, 设置为 false 即可
        username: nacos
        password: nacos
        server-addr: 127.0.0.1:8848
        namespace: 07656b3c-bb69-470a-a942-6ae27b5287cb
        group: FLY_GROUP
        metadata:
          management:
            context-path: ${server.servlet.context-path}/actuator

    loadbalancer:
      cache:
        ttl: 5s
      # 重试策略
      retry:
        maxRetriesOnSameServiceInstance: 0
        maxRetriesOnNextServiceInstance: 0
      clients:
        service-product:
          retry:
            maxRetriesOnSameServiceInstance: 0
            maxRetriesOnNextServiceInstance: 0

    gateway:
      discovery:
        locator:
          enabled: true
          #服务名小写
          lower-case-service-id: true
      globalcors:
        cors-configurations: # 跨域配置
          '[/**]': # 匹配所有路径
            allowed-origins: # 允许的域名
              - "http://localhost:7080"
            allowed-headers: "*" # 允许的请求头
            allowed-methods: "*" # 允许的方法
            allow-credentials: true # 是否携带cookie
      httpclient:
        pool:
          max-connections: 500
          max-idle-time: 10000


feign:
  httpclient:
    enabled: true
    max-connections: 200
    max-connections-per-route: 50

配置动态路由

创建配置文件命令空间

nacos 创建命名空间, 命名空间ID为: 07656b3c-bb69-470a-a942-6ae27b5287cb

配置动态路由

  • 点击配置列表
  • 选择命名空间
  • 点击新增按钮填写配置信息

填写配置信息

  • 新建配置文件, Data IDGroupGATEWAY_ROUTES
  • 配置格式选择 JSON
  • 配置文件如下:
json
[
  {
    "id": "gateway",
    "predicates": [
      {
        "name": "Path",
        "args": {
          "pattern": "/api/actuator/**"
        }
      }
    ],
    "uri": "lb://gateway",
    "filters": [
      {
        "name": "StripPrefix",
        "args": {
          "parts": "1"
        }
      }
    ]
  },
  {
    "id": "auth",
    "predicates": [
      {
        "name": "Path",
        "args": {
          "pattern": "/api/auth/**"
        }
      }
    ],
    "uri": "lb://auth",
    "filters": [
      {
        "name": "StripPrefix",
        "args": {
          "parts": "1"
        }
      }
    ]
  },
  {
    "id": "auth-client-demo",
    "predicates": [
      {
        "name": "Path",
        "args": {
          "pattern": "/api/auth-client-demo/**"
        }
      }
    ],
    "uri": "lb://auth-client-demo",
    "filters": [
      {
        "name": "StripPrefix",
        "args": {
          "parts": "1"
        }
      }
    ]
  }
]

路由配置

动态配置路由如下:

json
{
  "id": "auth",
  "predicates": [
    {
      "name": "Path",
      "args": {
        "pattern": "/api/auth/**"
      }
    }
  ],
  "uri": "lb://auth",
  "filters": [
    {
      "name": "StripPrefix",
      "args": {
        "parts": "1"
      }
    }
  ]
}
  • id: 路由唯一标识
  • predicates: 路由断言
  • uri: 目标服务地址
  • filters: 过滤器
  • order: 路由匹配顺序,数字越小优先级越高

predicates 断言

json
{
      "name": "Path",
      "args": {
        "pattern": "/api/auth/**"
      }
    }
  • Path: 断言,路径相匹配的进行路由
  • pattern: 匹配路径

filters 过滤器

json
{
      "name": "StripPrefix",
      "args": {
        "parts": "1"
      }
    }
  • StripPrefix: 转发时去除前缀1层路径(/api/)

创建全局过滤器

创建 GatewayGlobalFilter 全局过滤器

@Configuration
@SuppressWarnings("all")
public class GatewayGlobalFilter implements GlobalFilter {
    private static final Logger logger = LoggerFactory.getLogger(GatewayGlobalFilter.class);

    @Override
    public Mono<Void> filter(ServerWebExchange webExchange, GatewayFilterChain filterChain) {
        ServerHttpRequest request = webExchange.getRequest();
        String path = request.getURI().getPath();
        logger.info("path ==> " + path);
        return filterChain.filter(webExchange);
    }

}

启动类

@EnableAsync
@RefreshScope
@EnableDiscoveryClient
@SpringBootApplication
@EnableFeignClients({"com.github.itdachen"})
@ComponentScan(basePackages = {"com.github.itdachen"})
public class GatewayBootstrap {

    public static void main(String[] args) {
        SpringBootBootstrap.run(GatewayBootstrap.class);
    }

}

启动项目

启动项目, 控制台打印路由信息

测试

创建 http 文件, 通过网关理由转发进行登录和获取用户信息

### 账号密码登录
POST http://localhost:8080/api/auth/oauth/jwt/token
Content-Type: application/json

{
  "username": "admin",
  "password": "123456"
}


### 获取登录用户(auth)
GET http://localhost:8080/api/auth/current/user/details
Accept: application/json
Verified-Ticket: verifiedTicket # 校验
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJQUzUxMiJ9.eyJuaWNrTmFtZSI6IueOi-Wkp-WuuCIsInVzZXJUeXBlIjoiNCIsInVzZXJJZCI6IjEiLCJhY2NvdW50IjoiYWRtaW4iLCJpc3MiOiJjb20uZ2l0aHViLml0ZGFjaGVuIiwiaWF0IjoxNjkzMDYwODU0LCJleHAiOjE2OTMwNzg4NTR9.LXYbIG9Jl3_6I_-6-XqNKLTDX3WkltIkWkPIbioQBxTHHFikEhWws8qxyWTGjoZiyRMYW4wuhf3nyLEJeDFEgUGYgfRwXhIQSECSoJCEVF-nCdFXTbM2_isGW-Q1SjqCt0Yp2BT34Mbz5tKyCTgzVBGDW3_BIsJquTmHmAkR9Wev0YcSm4vmaUeIbJVYHrQUQVRjEPRAVQmv3ukrVQirxE8TBGGb7vm9rs-9xALzEmS-RTEO4suhnSZpXTy8qtIdUZeWiq2Hp2GNu4B4dfMht88jHUXJ-oufgLowqnJxH8qzwFHvsoFdxP1pBXqzjmEDWA3EiWhJEfLIVX1TqyJiWDkQJFUFAXlUtt3Dy2nSgP3gbMdzf3pV-nFPhdrUbHOd9yc_I2oXsRpE8bcsOwCLHyvOM5-Rw2z82cSSPApZPB66tu_FK_PdCjtS2L2yHe4L0JuTZOz4fFKXE0Q2hqL1ZLxqkeDumOIHvUldU0PUSlfFkWRpU2c_4wjZOPy7X7G_erwrWYorV5auIYTajh5gawEieIJp5AQOYrRdLgSNUEZf_M67hzrsnjHAhjHwKobEEP-rlZDKhJTIyEM1KaFZNg1bvXeAarUGDyBCwzNXetno8b2MwMb5wj7x2qSxL1fOBqPZWA-SbGHtWu44W4BSbtmy4F6Rhae21myZ_OFxaWM


### 获取登录用户(auth-client-demo)
GET http://localhost:8080/api/auth-client-demo/current/user/details
Accept: application/json
Verified-Ticket: verifiedTicket
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJQUzUxMiJ9.eyJuaWNrTmFtZSI6IueOi-Wkp-WuuCIsInVzZXJUeXBlIjoiNCIsInVzZXJJZCI6IjEiLCJhY2NvdW50IjoiYWRtaW4iLCJpc3MiOiJjb20uZ2l0aHViLml0ZGFjaGVuIiwiaWF0IjoxNjkzMDYwODU0LCJleHAiOjE2OTMwNzg4NTR9.LXYbIG9Jl3_6I_-6-XqNKLTDX3WkltIkWkPIbioQBxTHHFikEhWws8qxyWTGjoZiyRMYW4wuhf3nyLEJeDFEgUGYgfRwXhIQSECSoJCEVF-nCdFXTbM2_isGW-Q1SjqCt0Yp2BT34Mbz5tKyCTgzVBGDW3_BIsJquTmHmAkR9Wev0YcSm4vmaUeIbJVYHrQUQVRjEPRAVQmv3ukrVQirxE8TBGGb7vm9rs-9xALzEmS-RTEO4suhnSZpXTy8qtIdUZeWiq2Hp2GNu4B4dfMht88jHUXJ-oufgLowqnJxH8qzwFHvsoFdxP1pBXqzjmEDWA3EiWhJEfLIVX1TqyJiWDkQJFUFAXlUtt3Dy2nSgP3gbMdzf3pV-nFPhdrUbHOd9yc_I2oXsRpE8bcsOwCLHyvOM5-Rw2z82cSSPApZPB66tu_FK_PdCjtS2L2yHe4L0JuTZOz4fFKXE0Q2hqL1ZLxqkeDumOIHvUldU0PUSlfFkWRpU2c_4wjZOPy7X7G_erwrWYorV5auIYTajh5gawEieIJp5AQOYrRdLgSNUEZf_M67hzrsnjHAhjHwKobEEP-rlZDKhJTIyEM1KaFZNg1bvXeAarUGDyBCwzNXetno8b2MwMb5wj7x2qSxL1fOBqPZWA-SbGHtWu44W4BSbtmy4F6Rhae21myZ_OFxaWM

可以正常登录, 也能正常获取用户信息