阅读本文前可先参考

​​​​​​SpringCloud - Spring Cloud根/父项目,开发准备(二)_MinggeQingchun的博客-CSDN博客

一、API网关

引自百度百科

API网关,软件术语,两个相互独立的局域网之间通过路由器进行通信,中间的路由被称之为网关

任何一个应用系统如果需要被其他系统调用,就需要暴露 API,这些 API 代表着一个一个的功能点。

如果两个系统中间通信,在系统之间加上一个中介者协助 API 的调用,这个中介者就是 API 网关

API 网关是一个搭建在客户端和微服务之间的服务,我们可以在 API 网关中处理一些非业务功能的逻辑,例如权限验证、监控、缓存、请求路由等。

API 网关就像整个微服务系统的门面一样,是系统对外的唯一入口。有了它,客户端会先将请求发送到 API 网关,然后由 API 网关根据请求的标识信息将请求转发到微服务实例。

对于服务数量众多、复杂度较高、规模比较大的系统来说,使用 API 网关具有以下好处:

  • 客户端通过 API 网关与微服务交互时,客户端只需要知道 API 网关地址即可,而不需要维护大量的服务地址,简化了客户端的开发。
  • 客户端直接与 API 网关通信,能够减少客户端与各个服务的交互次数。
  • 客户端与后端的服务耦合度降低。
  • 节省流量,提高性能,提升用户体验。
  • API 网关还提供了安全、流控、过滤、缓存、计费以及监控等 API 管理功能。

常见的 API 网关实现方案主要有以下 5 种:

  • Spring Cloud Gateway
  • Spring Cloud Netflix Zuul
  • Kong
  • Nginx+Lua
  • Traefik

二、Gateway

Spring Cloud Gateway 是 Spring Cloud 团队基于 Spring 5.0、Spring Boot 2.0 和 Project Reactor 等技术开发的高性能 API 网关组件。

Spring Cloud Gateway 是基于 WebFlux 框架实现的,而 WebFlux 框架底层则使用了高性能的 Reactor 模式通信框架 Netty

Spring Cloud GateWay 最主要的功能就是路由转发,而在定义转发规则时主要涉及了以下三个核心概念

1、Route(路由)

2、Predicate(断言)

3、Filter(过滤)

核心概念描述
Route(路由)网关最基本的模块。它由一个 ID、一个目标 URI、一组断言(Predicate)和一组过滤器(Filter)组成。
Predicate(断言)路由转发的判断条件,我们可以通过 Predicate 对 HTTP 请求进行匹配,例如请求方式、请求路径、请求头、参数等,如果请求与断言匹配成功,则将请求转发到相应的服务。
Filter(过滤器)过滤器,我们可以使用它对请求进行拦截和修改,还可以使用它对上文的响应进行再处理。

注:其中 Route 和 Predicate 必须同时声明

Spring Cloud Gateway 工作流程

 1、客户端将请求发送到 Spring Cloud Gateway 上

 2、Spring Cloud Gateway 通过 Gateway Handler Mapping 找到与请求相匹配的路由,将其发送给 Gateway Web Handler。

 3、Gateway Web Handler 通过指定的过滤器链(Filter Chain),将请求转发到实际的服务节点中,执行业务逻辑返回响应结果。

 4、过滤器之间用虚线分开是因为过滤器可能会在转发请求之前(pre)或之后(post)执行业务逻辑。

 5、过滤器(Filter)可以在请求被转发到服务端前,对请求进行拦截和修改,例如参数校验、权限校验、流量监控、日志输出以及协议转换等。

 6、过滤器可以在响应返回客户端之前,对响应进行拦截和再处理,例如修改响应内容或响应头、日志输出、流量监控等。

 7、响应原路返回给客户端

三、Gateway应用

1、新建一个springboot Module(springcloud-7-service-eureka-gateway)

2、添加 spring-cloud-starter-gateway;spring-cloud-starter-netflix-eureka-client等 依赖

注:

在 gateway 网关服务中不能引入 spring-boot-starter-web 的依赖,否则会报错

spring-cloud-starter-gateway 使用的Netty服务器,而 spring-boot-starter-web 使用 的Tomcat服务器;Spring Cloud Gateway使用是基于WebFlux和Netty开发的,和传统的Tomcat服务器方式不同

<dependencies>

        <!--spring-cloud-starter-netflix-eureka-client-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>

        <!-- Spring cloud gateway 网关依赖
            特别注意:在 gateway 网关服务中不能引入 spring-boot-starter-web 的依赖,否则会报错
            Spring Cloud Gateway使用是基于WebFlux和Netty开发的,和传统的Tomcat服务器方式不同
        -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
    </dependencies>
<!--继承统一的父项目-->
    <parent>
        <groupId>com.company</groupId>
        <artifactId>springcloud-demo</artifactId>
        <version>1.0.0</version>
    </parent>

    <groupId>com.company</groupId>
    <artifactId>springcloud-7-service-eureka-gateway</artifactId>
    <version>1.0.0</version>

    <name>springcloud-7-service-eureka-gateway</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>

        <!--spring-cloud-starter-netflix-eureka-client-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>

        <!-- Spring cloud gateway 网关依赖
            特别注意:在 gateway 网关服务中不能引入 spring-boot-starter-web 的依赖,否则会报错
            Spring Cloud Gateway使用是基于WebFlux和Netty开发的,和传统的Tomcat服务器方式不同
        -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

3、application.properties配置文件

server.port=81

#eureka注册中心首页的Application这一栏
spring.application.name=springcloud-7-service-eureka-gateway

#每间隔5s,向Eureka服务注册中心发送一次心跳,证明服务是否依然“存活”
eureka.instance.lease-renewal-interval-in-seconds=2
#告诉服务端,如果10s之内没有发送心跳,就代表故障,将本服务踢出
eureka.instance.lease-expiration-duration-in-seconds=10
#告诉服务端,服务实例以IP作为链接,不是取机器名
eureka.instance.prefer-ip-address=false

#注册服务实例ID,,服务ID必须唯一 springcloud-7-service-eureka-gateway
eureka.instance.instance-id=${spring.application.name}:${server.port}
#注册中心的链接地址  http://eureka8761:8761/eureka,http://eureka8762:8762/eureka,http://eureka8763:8763/eureka
eureka.client.service-url.defaultZone=http://localhost:8761/eureka

#网关路由配置
#开启网关,默认开启
spring.cloud.gateway.enabled=true
#节点 routes 是一个List 对象,其中 routes 集合中中又包含多个对象,每个对象有三个属性(一个 索引[0]代表一个对象)
#路由 id,没有固定规则,但唯一
spring.cloud.gateway.routes[0].id=login-service-route
#匹配后提供服务的路由地址;uri统一资源定位符   url 统一资源标识符
spring.cloud.gateway.routes[0].uri=http://localhost:9001
#以下是断言条件,必选全部符合条件;断言是给某一个路由来设定的一种匹配规则 默认不能作用在动态路由上
#断言,路径匹配,只要Path匹配上了/doLogin 就往 uri 转发 并且将路径带上 注意:Path 中 P 为大写
#也可以全局匹配,如 /service/**
spring.cloud.gateway.routes[0].predicates[0]=Path=/doLogin
#只能是 GET 请求时,才能访问
spring.cloud.gateway.routes[0].predicates[0]=Method=GET

application.yml写法

server:
  port: 81

#eureka注册中心首页的Application这一栏
spring:
  application:
    name: springcloud-7-service-eureka-gateway
  #网关路由配置
  cloud:
    gateway:
      #开启网关,默认开启
      enabled: true
      #节点 routes 是一个List 对象,其中 routes 集合中中又包含多个对象,每个对象有三个属性(一个 索引[0]代表一个对象)
      routes:
        #路由 id,没有固定规则,但唯一
        - id: login-service-route
          #匹配后提供服务的路由地址;uri统一资源定位符   url 统一资源标识符
          uri: http://localhost:9001
          #以下是断言条件,必选全部符合条件;断言是给某一个路由来设定的一种匹配规则 默认不能作用在动态路由上
          predicates:
            #断言,路径匹配,只要Path匹配上了/doLogin 就往 uri 转发 并且将路径带上 注意:Path 中 P 为大写
            #也可以全局匹配,如 /service/**
            - Path=/doLogin
            #只能是 GET,POST 请求时,才能访问
            - Method=GET,POST

eureka:
  instance:
    #每间隔5s,向Eureka服务注册中心发送一次心跳,证明服务是否依然“存活”
    lease-renewal-interval-in-seconds: 2
    #告诉服务端,如果10s之内没有发送心跳,就代表故障,将本服务踢出
    lease-expiration-duration-in-seconds: 10
    #告诉服务端,服务实例以IP作为链接,不是取机器名
    prefer-ip-address: false
    #注册服务实例ID,,服务ID必须唯一 springcloud-7-service-eureka-gateway
    instance-id: ${spring.application.name}:${server.port}
  #注册中心的链接地址  http://eureka8761:8761/eureka,http://eureka8762:8762/eureka,http://eureka8763:8763/eureka
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka


注:

(1)Gateway 网关建议 使用 yml 文件格式配置,以properties配置比较繁琐,一般公司项目也建议采取 yml格式

(2)不管 application.properties 还是 application.yml 写法,都要注意 断言 predicates 处的 Path=/doLogin 和  Method=GET,POST写法,不然报如下错误

***************************
APPLICATION FAILED TO START
***************************

Description:

Binding to target [Bindable@4a6facb0 type = java.util.List<org.springframework.cloud.gateway.handler.predicate.PredicateDefinition>, value = 'provided', annotations = array<Annotation>[@javax.validation.constraints.NotEmpty(message={javax.validation.constraints.NotEmpty.message}, groups=[], payload=[]), @javax.validation.Valid()]] failed:

    Property: spring.cloud.gateway.routes[0].predicates[0].path
    Value: /doLogin
    Origin: class path resource [application.yml]:23:21
    Reason: The elements [spring.cloud.gateway.routes[0].predicates[0].path,spring.cloud.gateway.routes[0].predicates[1].method] were left unbound.
    Property: spring.cloud.gateway.routes[0].predicates[1].method
    Value: GET,POST
    Origin: class path resource [application.yml]:25:23
    Reason: The elements [spring.cloud.gateway.routes[0].predicates[0].path,spring.cloud.gateway.routes[0].predicates[1].method] were left unbound.

  

4、在 Spring Boot 的启动类中,添加 @EnableEurekaClient 注解开启 Eureka 客户端功能(Gateway网关也是eureka的客户端)

@EnableEurekaClient  //Gateway网关也是eureka的客户端
@SpringBootApplication
public class EurekaGateway7Application {
    public static void main(String[] args) {
        SpringApplication.run(EurekaGateway7Application.class, args);
    }
}

5、创建一个服务提供者  springcloud-7-service-eureka-gateway-login

依赖

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!--spring-cloud-starter-netflix-eureka-client-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
    </dependencies>

application.properties

server.port=9001

#设置应用名称,对应Eureka控制台下 DS Replicas 的 Application(集群部署服务提供者,Application一致,对应多个eureka.instance.instance-id)
spring.application.name=springcloud-7-service-eureka-gateway-login

#每间隔5s,向Eureka服务注册中心发送一次心跳,证明服务是否依然“存活”
eureka.instance.lease-renewal-interval-in-seconds=5
#告诉服务端,如果10s之内没有发送心跳,就代表故障,将本服务踢出
eureka.instance.lease-expiration-duration-in-seconds=10
#告诉服务端,服务实例以IP作为链接,不是取机器名
eureka.instance.prefer-ip-address=false

#注册服务实例ID,,服务ID必须唯一
eureka.instance.instance-id=springcloud-7-service-eureka-gateway-login
#注册中心的链接地址  http://localhost:8761/eureka
eureka.client.service-url.defaultZone=http://localhost:8761/eureka

 controller测试类

@RestController
public class LoginController {
    @GetMapping("/doLogin")
    public String doLogin(String name, String pwd) {
        System.out.println(name);
        System.out.println(pwd);
        // token
        String token = UUID.randomUUID().toString();
        return token;
    }
}

6、分别启动本地 eureka,gateway,login-service ,输入访问 http://localhost:81/doLogin

注:

这里启动 Gateway网关模块,会明显的在控制台下方看到输出:

 Netty started on port(s):81

服务者自己的端口 9001 访问 自然无问题 

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐