微服务-- Gateway服务网关

Spring Cloud Gateway 是 Spring Cloud 的一个全新项目,该项目是基于 Spring 5.0,Spring Boot 2.0 和 Project Reactor 等响应式编程和事件流技术开发的网关,它旨在为微服务架构提供一种简单有效的统一的 API 路由管理方式。

为什么需要网关

在微服务架构中,网关(Gateway)作为统一入口,承担着多个关键角色。

核心功能特性

  • 请求路由:网关根据请求的路径、方法和其他参数,将请求路由到相应的微服务实例。这种集中管理的方式简化了客户端与多个微服务之间的交互。
  • 权限控制:网关可以实现用户身份验证和授权,确保只有经过授权的用户才能访问特定的服务。这提供了一个安全层,保护后端服务不受未授权访问。
  • 限流:为了防止系统过载,网关可以设置请求限制,以控制流量。例如,可以限制每秒的请求数量,确保服务的稳定性和可靠性。

架构图:

权限控制:

  • 网关负责校验用户请求的资格,确保只有经过身份验证和授权的用户才能访问特定的微服务。如果未授权,网关将拦截请求并返回相应的错误信息。

路由和负载均衡:

  • 所有请求都必须经过网关,网关根据预设的规则将请求转发到合适的微服务。这一过程称为路由。
  • 当多个服务实例可用时,网关还需要执行负载均衡,以分散流量并提高系统的可用性和响应速度。

限流:

  • 在高流量情况下,网关通过限制请求速率来保护后端服务,确保它们不会因过载而崩溃。这通常基于下游服务的处理能力进行调整,以平衡请求流量。

Spring Cloud中的网关实现

Zuul:

  • 类型:基于Servlet的阻塞式编程。
  • 特点:提供路由、负载均衡和过滤功能,但由于其阻塞特性,在高并发场景下可能会导致性能瓶颈。
  • 适用场景:适合简单的微服务应用,但在对性能要求较高的情况下可能不够理想。

Spring Cloud Gateway:

  • 类型:基于Spring 5中提供的WebFlux,响应式编程。
  • 特点:具备更好的性能,能够处理更多的并发请求,支持非阻塞IO。提供了更灵活的路由和过滤功能,并且集成了Spring生态中的其他组件。
  • 适用场景:适合需要高性能、高并发的微服务架构,是现代微服务应用的推荐选择。

gateway快速入门

第一步:添加依赖

XML 复制代码
        <!-- 不可以引入spring-boot-starter-web会有冲突 -->
        <!--网关-->
        <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-gateway -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
            <version>4.1.0</version>
        </dependency>

第二步:配置好注册中心[按照Eureka、zookeeper、nacos客户端配置即可]

第三步:编写properties

XML 复制代码
# 服务端口
server.port=8082

# 服务名称
spring.application.name=service2

# Nacos 服务地址
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848

# 启用 Sentinel,并连接 Sentinel Dashboard
spring.cloud.sentinel.transport.dashboard=127.0.0.1:8080
spring.cloud.sentinel.transport.port=8720  # 本地 Sentinel 客户端的监控端口
# 启用 Sentinel
spring.cloud.sentinel.enabled=true

# 网关配置
# 定义路由的唯一标识符
spring.cloud.gateway.routes[0].id=route_to_service2
# 设置目标服务的URI
spring.cloud.gateway.routes[0].uri=http://localhost:8082
# 配置路由的断言,这里指定路径匹配规则
spring.cloud.gateway.routes[0].predicates[0]=Path=/service2/**

启动网关服务

然后可以通过访问如下 URL 来测试路由功能:

XML 复制代码
http://localhost:8082/service2/test

网关路由的流程图

整个访问的流程如下:

断言工厂

在 Spring Cloud Gateway 中,断言工厂(Predicate Factory)用于定义请求路由的条件。它们通过处理配置文件中的字符串,来决定哪些请求应该被转发到具体的服务。

常用断言工厂

名称 说明 示例
After 匹配在某个时间点后的请求 After=2037-01-20T17:42:47.789-07:00[America/Denver]
Before 匹配在某个时间点之前的请求 Before=2031-04-13T15:14:47.433+08:00[Asia/Shanghai]
Between 匹配在两个时间点之间的请求 Between=2037-01-20T17:42:47.789-07:00[America/Denver], 2037-01-21T17:42:47.789-07:00[America/Denver]
Cookie 请求必须包含某些 cookie Cookie=chocolate, ch.p
Header 请求必须包含某些 header Header=X-Request-Id, \d+
Host 请求必须访问特定的 host(域名) Host=**.somehost.org,**.anotherhost.org
Method 请求方式必须是指定方式 Method=GET,POST
Path 请求路径必须符合指定规则 Path=/red/{segment},/blue/**
Query 请求参数必须包含指定参数 Query=name, JackQuery=name
RemoteAddr 请求者的 IP 必须在指定范围 RemoteAddr=192.168.1.1/24
Weight 权重处理

使用示例

以 Path 断言工厂为例,假设我们希望将所有访问 /user/** 的请求转发到某个服务,可以在 application.properties 文件中这样配置:

XML 复制代码
spring.cloud.gateway.routes[0].id=user_route
spring.cloud.gateway.routes[0].uri=http://localhost:8080
spring.cloud.gateway.routes[0].predicates[0]=Path=/user/**

虽然有多种断言工厂可供使用,但熟悉 Path 断言工厂通常足以应对大多数路由需求。

过滤器工厂

GatewayFilter 是 Spring Cloud Gateway 提供的一种机制,用于处理进入网关的请求以及微服务返回的响应。

路由过滤器的种类

Spring 提供了多种路由过滤器工厂,常用的包括:

名称 说明
AddRequestHeader 给当前请求添加一个请求头
RemoveRequestHeader 移除请求中的一个请求头
AddResponseHeader 给响应结果中添加一个响应头
RemoveResponseHeader 从响应结果中移除一个响应头
RequestRateLimiter 限制请求流量

请求头过滤器示例

以 AddRequestHeader 为例,假设我们的需求是给所有进入 userservice 的请求添加一个请求头:Truth=Itcast is freaking awesome!。可以在 application.yml 文件中这样配置:

XML 复制代码
spring:
  cloud:
    gateway:
      routes:
      - id: user-service 
        uri: lb://userservice 
        predicates: 
        - Path=/user/** 
        filters: # 过滤器
        - AddRequestHeader=Truth, Itcast is freaking awesome! # 添加请求头

通过这种方式,该过滤器仅对访问 userservice 的请求生效。

默认过滤器

如果希望某个过滤器对所有路由都生效,可以将过滤器配置在 default-filters 下:

XML 复制代码
spring:
  cloud:
    gateway:
      routes:
      - id: user-service 
        uri: lb://userservice 
        predicates: 
        - Path=/user/**
      default-filters: # 默认过滤项
      - AddRequestHeader=Truth, Itcast is freaking awesome! 

总结

过滤器的作用是什么?

  • 对路由的请求或响应进行加工处理,例如添加请求头。
  • 配置在特定路由下的过滤器仅对该路由的请求生效。

default-filters 的作用是什么?

  • default-filters 中的过滤器会对所有路由生效。

全局过滤器

全局过滤器是 Spring Cloud Gateway 中的一种机制,用于对所有请求和响应进行统一的处理。与路由特定的过滤器不同,全局过滤器可以应用于网关中的所有路由,提供了一种集中管理请求和响应的方法。

全局过滤器作用

全局过滤器用于处理所有进入网关的请求和微服务响应,功能与GatewayFilter类似。不同之处在于GatewayFilter通过配置定义,其处理逻辑是固定的;而GlobalFilter的逻辑需要开发者自行编写代码实现。

实现方式是通过实现GlobalFilter接口:

java 复制代码
public interface GlobalFilter {
    Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain);
}

在filter方法中可以编写自定义逻辑,实现如下功能:

  • 登录状态判断
  • 权限校验
  • 请求限流等

自定义全局过滤器

需求

定义一个全局过滤器,拦截请求,判断请求参数是否符合以下条件:

  1. 参数中是否有authorization
  2. authorization参数值是否为admin
  3. 如果满足这两个条件,则放行;否则拦截请求。

实现

在网关中定义一个过滤器:

java 复制代码
package cn.itcast.gateway.filters;

import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.util.MultiValueMap;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

@Order(-1)
@Component
public class AuthorizeFilter implements GlobalFilter {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // 1.获取请求参数
        MultiValueMap<String, String> params = exchange.getRequest().getQueryParams();
        // 2.获取authorization参数
        String auth = params.getFirst("authorization");
        // 3.校验
        if ("admin".equals(auth)) {
            // 放行
            return chain.filter(exchange);
        }
        // 4.拦截
        // 4.1.禁止访问,设置状态码
        exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN);
        // 4.2.结束处理
        return exchange.getResponse().setComplete();
    }
}

过滤器执行顺序

请求进入网关后,会经过三类过滤器:

  1. 当前路由的过滤器
  2. DefaultFilter
  3. GlobalFilter

请求路由后,会将这些过滤器合并成一个过滤器链,并按照顺序依次执行。

排序规则

  • 每个过滤器必须指定一个int类型的order值,order值越小,优先级越高,执行顺序越靠前。
  • GlobalFilter通过实现Ordered接口或使用@Order注解来指定order值。
  • 路由过滤器和defaultFilter的order由Spring自动指定,默认按声明顺序递增。
  • 当多个过滤器的order值相同时,执行顺序为:defaultFilter > 路由过滤器 > GlobalFilter。

更多详细内容,可查看源码:

  • org.springframework.cloud.gateway.route.RouteDefinitionRouteLocator#getFilters()方法加载defaultFilters和路由的filters并进行合并。
  • org.springframework.cloud.gateway.handler.FilteringWebHandler#handle()方法加载全局过滤器,与前面的过滤器合并后根据order排序,组织过滤器链。

跨域问题

什么是跨域问题

跨域指的是在不同的域名、端口或协议之间进行请求。具体包括以下几种情况:

跨域问题是指浏览器出于安全考虑,禁止发起来自不同域的 AJAX 请求,因此请求会被浏览器拦截。

解决方案 :CORS(跨域资源共享),可以参考阮一峰的网络日志了解更多。

解决跨域问题

在 Gateway 服务的 application.yml 文件中,添加以下配置,以实现全局的跨域处理:

XML 复制代码
spring:
  cloud:
    gateway:
      globalcors: # 全局的跨域处理
        add-to-simple-url-handler-mapping: true # 解决 OPTIONS 请求被拦截问题
        corsConfigurations:
          '[/**]': # 所有路径的跨域配置
            allowedOrigins: # 允许哪些网站的跨域请求 
              - "http://localhost:8090"
            allowedMethods: # 允许的跨域 AJAX 请求方式
              - "GET"
              - "POST"
              - "DELETE"
              - "PUT"
              - "OPTIONS"
            allowedHeaders: "*" # 允许在请求中携带的头信息
            allowCredentials: true # 是否允许携带 cookie
            maxAge: 360000 # 这次跨域检测的有效期

总结

通过配置 CORS,可以有效解决跨域请求的问题,使得不同源之间的 AJAX 请求能够顺利进行。

相关推荐
禁默38 分钟前
深入浅出:AWT的基本组件及其应用
java·开发语言·界面编程
Cachel wood1 小时前
python round四舍五入和decimal库精确四舍五入
java·linux·前端·数据库·vue.js·python·前端框架
Code哈哈笑1 小时前
【Java 学习】深度剖析Java多态:从向上转型到向下转型,解锁动态绑定的奥秘,让代码更优雅灵活
java·开发语言·学习
gb42152871 小时前
springboot中Jackson库和jsonpath库的区别和联系。
java·spring boot·后端
程序猿进阶1 小时前
深入解析 Spring WebFlux:原理与应用
java·开发语言·后端·spring·面试·架构·springboot
zfoo-framework1 小时前
【jenkins插件】
java
风_流沙1 小时前
java 对ElasticSearch数据库操作封装工具类(对你是否适用嘞)
java·数据库·elasticsearch
ProtonBase2 小时前
如何从 0 到 1 ,打造全新一代分布式数据架构
java·网络·数据库·数据仓库·分布式·云原生·架构
乐之者v2 小时前
leetCode43.字符串相乘
java·数据结构·算法