Springboot集成Gateway实现API服务网关-07

GateWay简介

Spring Cloud Gateway 为 SpringBoot 应用提供了API网关支持,具有强大的智能路由与过滤器功能,本文将对其用法进行详细介绍。

网关术语

关于网关三个重要的概念如下:

  • Route(路由):路由是构建网关的基本模块,它由ID,目标URI,一系列的断言和过滤器组成,如果断言为true则匹配该路由;
  • Predicate(断言):指的是Java 8 的 Function Predicate。 输入类型是Spring框架中的ServerWebExchange。 这使开发人员可以匹配HTTP请求中的所有内容,例如请求头或请求参数。如果请求与断言相匹配,则进行路由;
  • Filter(过滤器):指的是Spring框架中GatewayFilter的实例,使用过滤器,可以在请求被路由前后对请求进行修改,比如参数效验、权限效验、流量监控、日志输出、协议转换等。

主要功能

Gateway是在Spring生态系统之上构建的API网关服务,Gateway旨在提供一种简单而有效的方式来对API进行路由,以及提供一些强大的过滤器功能, 例如:熔断、限流、重试等。

Spring Cloud Gateway 具有如下特性:

  • 基于Spring Framework 5, Project Reactor 和 Spring Boot 2.0 进行构建;
  • 动态路由:能够匹配任何请求属性;
  • 可以对路由指定 Predicate(断言)和 Filter(过滤器);
  • 集成Hystrix的断路器功能;
  • 集成 Spring Cloud 服务发现功能;
  • 易于编写的 Predicate(断言)和 Filter(过滤器);
  • 请求限流功能;
  • 支持路径重写。

调用执行过程

  1. Gateway Client向Gateway Server发送请求
  2. 请求首先会被HttpWebHandlerAdapter进行提取组装成网关上下文
  3. 然后网关的上下文会传递到DispatcherHandler,它负责将请求分发给RoutePredicateHandlerMapping
  4. RoutePredicateHandlerMapping负责路由查找,并根据路由断言判断路由是否可用
  5. 如果过断言成功,由FilteringWebHandler创建过滤器链并调用
  6. 请求会一次经过PreFilter--微服务--PostFilter的方法,最终返回响应

为什么要使用网关

看下面的图即可:

  • 传统应用部署模式:
  • 采用网关后的部署模式:

此测试中使用了Consul注册中心

GateWay网关服务实现

pom.xml

依赖版本可参考 springbootSeries 模块中pom.xml文件中的版本定义

xml 复制代码
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-consul-discovery</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>

application.yml 配置

因为网关配置比较复杂,会有一些数组类的配置,所以这里选用yml格式。

yaml 复制代码
server:
    port: 19000

debug: false

spring:
    application:
        name: springbootAPIGateway
    profiles:
        active: dev
    cloud:
        consul:
            discovery:
                service-name: ${spring.application.name}
            host: localhost
            port: 8500
        gateway:
            routes:
                - id: path_route #路由标识、区别于其他route
                  order: 9000  #用于多个route之间的排序,数值越小排序越靠前,匹配优先级越高
                  uri:  http://localhost:18096  # 路由指向的目的地uri,即客户端请求最终被转发到的微服务
                  predicates:
                    - Path=/api/load/v1/**  #断言的作用是进行条件判断,只有断言都返回真,才会真正的执行路由
    main:
        web-application-type: reactive

SpringbootApplication启动类

这里主要是添加了Consul服务发现注解@EnableDiscoveryClient

java 复制代码
@Slf4j
@SpringBootApplication(scanBasePackages = {"com.korgs",  "cn.hutool.extra.spring"})
@Configuration
@EnableConfigurationProperties
@ServletComponentScan
@RestController
@EnableDiscoveryClient
public class SpringbootApiGatewayApplication {

	public static void main(String[] args) {
		SpringApplication.run(SpringbootApiGatewayApplication.class, args);
	}

	@GetMapping("/helloworld")
	public BaseResponse helloWorld(){
		log.info( LogGenerator.trackLog()
				+ "msg=" + "I am busy to handle this request.");
		return BaseResponse.success("hello world");
	}
}

被代理的springboot服务

这个就是一个普通的应用,没什么特殊的。

pom.xml

这里主要配置了注册中心,如果不需要可删除掉consul相关的配置

xml 复制代码
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-consul-discovery</artifactId>
        </dependency>
    </dependencies>

application.properties 配置

这里主要配置了注册中心,如果不需要可删除掉consul相关的配置

shell 复制代码
spring.profiles.active = dev
spring.application.name=springbootGatewayServer
server.port=18096

spring.cloud.consul.host=localhost
spring.cloud.consul.port=8500
spring.cloud.consul.discovery.service-name=${spring.application.name}

SpringbootApplication启动类

java 复制代码
@Slf4j
@SpringBootApplication(scanBasePackages = {"com.korgs",  "cn.hutool.extra.spring"})
@Configuration
@EnableConfigurationProperties
@ServletComponentScan
@RestController
@EnableDiscoveryClient
public class SpringbootGatewayServerApplication {

	public static void main(String[] args) {
		SpringApplication.run(SpringbootGatewayServerApplication.class, args);
	}

	@GetMapping("/helloworld")
	public String helloWorld(){
		log.info( LogGenerator.trackLog()
				+ "msg=" + "I am busy to handle this request.");
		return "hello world";
	}
}

实现被代理的Restful API

java 复制代码
@Slf4j
@RestController
@RequestMapping("/api/load")
public class LoadBalanceController {

    @Value("${server.port}")
    private String serverPort;

    @GetMapping("/v1/hello-content/{uuid}")
    public BaseResponse<String> loadHelloContent(@PathVariable  String uuid){
        String str = LogGenerator.trackLog()
                + " uuid=" + uuid + " I am busy to handle this request."
                + " serverPort=" + serverPort;
        log.info( str );
        return BaseResponse.success(str);
    }
}

源码下载

涉及模块:

  • springcloud-api-gateway:19000 ,网关服务
  • springcloud-gateway-server:18096 ,这个就是一个普通的应用,没什么特殊的

源码下载:

源码运行方法:

访问 : http://localhost:19000/api/load/v1/hello-content/2会发现端口号19000不变,但实际访问了18096服务的实现。

注意事项

断言Predicate配置

注意:此应用的spring文件最好用yaml来配置,配置的重点就是uri 和 predicates 正常来讲是一一对应的,比如下面配置中,最终访问地址是uri+path,但Path不能随便写,比如把/api去掉,如果去掉了就不能访问到真实地址了,而且后台好像也有一个验证的过程,最恶心的是一直提示404。

yml 复制代码
        gateway:
            routes:
                - id: path_route
                  uri:  http://localhost:18096
                  predicates:
                    - Path=/api/load/v1/**

断言Predicate类别说明

  1. After:匹配在指定日期时间之后发生的请求。
  2. Before:匹配在指定日期之前发生的请求。
  3. Between:需要指定两个日期参数,设定一个时间区间,匹配此时间区间内的请求。
  4. Cookie:需要指定两个参数,分别为name和regexp(正则表达式),也可以理解Key和Value,匹配具有给定名称且其值与正则表达式匹配的Cookie。
  5. Header:需要两个参数header和regexp(正则表达式),也可以理解为Key和Value,匹配请求携带信息。
  6. Host:匹配当前请求是否来自于设置的主机。
  7. Method:可以设置一个或多个参数,匹配HTTP请求,比如GET、POST
  8. Path:匹配指定路径下的请求,可以是多个用逗号分隔
  9. Query:需要指定一个或者多个参数,一个必须参数和一个可选的正则表达式,匹配请求中是否包含第一个参数,如果有两个参数,则匹配请求中第一个参数的值是否符合正则表达式。
  10. RemoteAddr:匹配指定IP或IP段,符合条件转发。
  11. Weight:需要两个参数group和weight(int),实现了路由权重功能,按照路由权重选择同一个分组中的路由

https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#gateway-request-predicates-factories

相关推荐
徐*红19 分钟前
java 线程池
java·开发语言
尚学教辅学习资料19 分钟前
基于SSM的养老院管理系统+LW示例参考
java·开发语言·java毕设·养老院
2401_8576363919 分钟前
计算机课程管理平台:Spring Boot与工程认证的结合
java·spring boot·后端
1 9 J21 分钟前
Java 上机实践4(类与对象)
java·开发语言·算法
Code apprenticeship22 分钟前
Java面试题(2)
java·开发语言
憨子周1 小时前
2M的带宽怎么怎么设置tcp滑动窗口以及连接池
java·网络·网络协议·tcp/ip
霖雨3 小时前
使用Visual Studio Code 快速新建Net项目
java·ide·windows·vscode·编辑器
SRY122404193 小时前
javaSE面试题
java·开发语言·面试
Fiercezm3 小时前
JUC学习
java
无尽的大道3 小时前
Java 泛型详解:参数化类型的强大之处
java·开发语言