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

相关推荐
talenteddriver2 分钟前
web: jwt令牌构成、创建的基本流程及原理
java·开发语言·python·网络协议·web
码农水水2 分钟前
宇树科技Java被问:数据库连接池的工作原理
java·数据库·后端·oracle
Seven973 分钟前
回溯算法总结
java
小鸡脚来咯3 分钟前
软链接的作用和用途
java·ide·eclipse
这周也會开心3 分钟前
双栈实现队列以及双队列实现栈
java·开发语言
yangmf20407 分钟前
INFINI Gateway 助力联想集团 ES 迁移升级
大数据·数据库·elasticsearch·搜索引擎·gateway·全文检索
廋到被风吹走8 分钟前
【Spring】Spring Batch 详细介绍
java·spring·batch
北极糊的狐8 分钟前
MQTT报错:Exception in thread main java.lang.at io.github.pnoker.common.sdk.utils.ParseUtils.decodeHex
java·开发语言
weixin1997010801613 分钟前
TikTokitem_search_video关键词视频列表接口对接全攻略:从入门到精通
java·服务器·音视频
雪花desu24 分钟前
【Hot100-Java中等】:字母异位词分组
java·算法·leetcode·哈希表