微服务cloud

微服务

微服务是一种经过良好架构设计的分布式架构方案,微服务架构特征:

  • 单一职责:微服务拆分粒度更小,每一个服务都对应唯一的业务能力,做到单一职责,避免重复业务开发
  • 面向服务:微服务对外暴露业务接口
  • 自治:团队独立、技术独立、数据独立、部署独立
  • 隔离性强:服务调用做好隔离、容错、降级,避免出现级联问题

单体架构:

  • 简单方便,高度耦合、扩展性差,适合小型项目

分布式架构特点:

  • 松耦合,扩展性好,但架构复杂,难度大。适合大型互联网项目

微服务:一种良好的分布式架构方案

  • 优点:拆分粒度更小、服务更独立、耦合度更低
  • 缺点:架构非常复杂,运维、监控、部署难度提高
DubboSpringCloudSpringCloudAlibaba
注册中心zookeeper、RedisEureka、ConsulNacos、Eureka
服务远程调用Dubbo 协议Feign(http 协议)Dubbo、Feign
配置中心SpringCloudConfigSpringCloudConfig、Nacos
服务网关SpringCloudGateway、zuulSpringCloudGateway、Zuul
服务监控和保护dubbo-admin 功能弱HystrixSentinel

springCloud

服务注册发现:Eureka、Nacos、Consul

统一配置管理:Spring Cloud Config、Nacos

服务远程调用:OpenFeign、Dubbo

统一网关路由:Spring Cloud Gateway、zuul

服务链路监控:Zipkin、Sleuth

流控、降级、保护:Hystix、Sentinel

服务拆分及远程调用

1、不同微服务,不要重复开发相同业务

2、微服务数据独立,不要访问其他微服务的数据库

3、微服务可以将自己的业务暴露为接口,供其他微服务调用

  • 微服务需要根据业务模块拆分,做到单一职责,不要重复开发相同业务
  • 微服务可以将业务暴露为接口,供其他微服务使用
  • 不同微服务都应该有自己独立的数据库

远程调用方式分析

从订单向用户发起远程调用

user 服务向外暴露了一个接口 http://localhost:8091/user/{id}

订单模块直接向用户模块发起 http 请求(RestTemplate)

/**
 * 创建 RestTemplate 并注入 Spring 容器
 */
@Bean
public RestTemplate restTemplate() {
    return new RestTemplate();
}

service

@Autowired
private OrderMapper orderMapper;
@Autowired
private RestTemplate restTemplate;

public Order queryOrderById(Long orderId) {
    // 1.查询订单
    Order order = orderMapper.findById(orderId);
    // 2.利用 RestTemplate 发起 http 请求,查询用户
    // 2.1 url 路径
    String url = "http://localhost:8091/user/" + order.getUserId();
    // 2.2 发送 http 请求,实现远程调用
    User user = restTemplate.getForObject(url, User.class);
    // 3.封装 user 到 order
    order.setUser(user);
    // 4.返回
    return order;
}

消费者与提供者

  • 服务提供者:一次业务中,被其他微服务调用的服务。(提供接口给其他微服务)
  • 服务消费者:一次业务中,调用其他微服务的服务。(调用其他微服务提供的接口)

一个服务既可以是提供者又可以是消费者(提供者和消费者角色是相对的)

Eureka 注册中心

Eureka 的作用

  • 消费者如何获取服务提供者具体的信息
    • 服务提供者启动时向 eureka 注册自己的信息
    • eureka 保存这些信息
    • 消费者根据服务名称向 eureka 拉取提供者信息
  • 如果又多个服务提供者,消费者如何选择
    • 服务消费者利用负载均衡算法,从服务列表中挑选一个
  • 消费者如何感知服务提供者健康状态
    • 服务提供者会每隔 30 秒向 EurekaServer 发送心跳请求,报告健康状态
    • eureka 会更新记录服务列表信息,心跳不正常会被剔除
    • 消费者就可以拉取到最新的信息

在 Eureka 架构中,微服务角色有两类

  • EurekaServer:服务端,注册中心
    • 记录服务信息
    • 心跳监控
  • EurekaClient:客户端
    • Provider:服务提供者
      • 注册自己的信息到 EurekaServer
      • 每隔 30 秒向 EurekaServer 发送心跳
    • consumer:服务消费者
      • 根据服务名称从 EurekaServer 拉取服务列表
      • 基于服务列表做负载均衡,选中一个微服务后发起远程调用

搭建 EurekaServer

创建项目 引入 spring-cloud-starter-netflix-eureka-server 依赖

<dependencies>
    <!--eureka 服务器-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
    </dependency>
</dependencies>

编写启动类,添加 @EnableEurekaServer 注解

@EnableEurekaServer
@SpringBootApplication
public class EurekaApplication {
    public static void main(String[] args) {
        SpringApplication.run(EurekaApplication.class,args);
    }
}

编写 yml 文件配置

server:
  port: 10086
spring:
  application:
    name: eurekaserver
eureka:
  client:
    service-url: # eureka 的地址信息
      defaultZone: http://127.0.0.1:10086/eureka
服务注册
  • 引入 eureka-client 依赖
  • 在 application.yml 中配置 eureka 地址
服务的发现/拉取

服务拉取是基于服务名称获取服务列表,然后对服务列表做负载均衡

1、修改 OrderService 代码,修改访问的 url 路径,用服务名代替 ip、端口:

String url = "http://userservice/user/" + order.getUserId();

2、在 order-service 项目的启动类 OrderApplication 中的 RestTemplate 添加负载均衡注解:

@Bean
@LoadBalanced
public RestTemplate restTemplate() {
    return new RestTemplate();
}

Riboon 负载均衡

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KnHNXlig-1674732672886)(C:\Users\xiaobai\AppData\Roaming\Typora\typora-user-images\image-20221124163451711.png)]

负载均衡策略

Ribbon 的负载均衡规则是一个叫做 IRule 的接口来定义的,每一个子接口都是一种规则

内置负载均衡规则类规则描述
RoundRobinRule简单轮询服务列表来选择服务器。它是 Ribbon 默认的负载均衡规则
AvailabilityFilteringRule对以下两种服务器及进行忽略:
(1)在默认情况下,这台服务器如果 3 次链接失败,这台服务器就会被设置为“短路”状态。短路状态将持续 30 秒,如果再次连接失败,短路的持续时间就会几何级地增加。
(2)并发数过高的服务器。如果一个服务器的并发连接数过高,配置了 AvailabilityFilteringRule 规则的客户端也会将其忽略。并发连接数的上限,可以由客户端的..ActiveConnectionsLimit 属性进行配置。
weightedResponseTimeRule为每一个服务器赋予一个权重值。服务器响应时间越长,这个服务器的权重就越小。这个规则会随机选择服务器,这个权重会英雄服务器的选择。
ZoneAvoidanceRule以区域可用的服务器为基础进行服务器的选择。使用 Zone 对服务器进行分类,这个 Zone 可以理解为一个机房、一个机架等。而后再对 Zone 内的多个服务做轮询。
BestAvailableRuel忽略那些短路的服务器,并选择并发数较低的服务器。
RandomRule随机选择一个可用的服务器
RetryRule重试机制的选择逻辑

通过定义 IRule 实现可以修改负载均衡规则,有两种方式:

1、代码方式:在 order-service 中的 OrderApplication 类中,定义一个新的 IRule

@Bean
public IRule randomRule(){
    return new RandomRule();
}

2、配置文件方式:在 order-service 的 application.yml 文件中,添加新的配置也可以修改规则

userservice:
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule # 负载均衡规则

饥饿加载

Ribbon 默认是在采用懒加载,即第一次访问时才会去创建 LoadBanlanceClient,请求时间会很长。

而饥饿加载则会在项目启动时创建,降低第一次访问的耗时,通过下面配置开启饥饿加载

ribbon:
  eager-load:
    enabled: true # 开启饥饿加载
    clients: # 指定饥饿加载的服务名称
		- userservice

总结

Ribbon 负载均衡规则

  • 规则接口是 IRule
  • 默认实现是 ZoneAvoidanceRule,根据 zone 选择服务列表,然后轮询

负载均衡自定义方式

  • 代码方式:配置灵活,但修改时需要重新打包发布
  • 配置方式:直观,方便,无需重新打包发布,但是无法做到全局配置

饥饿加载

  • 开启饥饿加载
  • 指定饥饿加载的微服务名称

Nacos 注册中心

Nacos 是阿里巴巴的产品,现在是 SpringCloud 中的一个组件。相比 Eureka 功能更加丰富,在国内受欢迎程度较高。

单机模式:

1.首先通过cmd进入到nacos文件夹里面bin目录
2.然后输入命令startup.cmd -m standalone 这里是将nacos以单机模式运行

Nacos的依赖

父工程:

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-alibaba-dependencies</artifactId>
    <version>2.2.5.RELEASE</version>
    <type>pom</type>
    <scope>import</scope>
</dependency>

客户端:

<!-- nacos客户端依赖包 -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

配置文件

spring:
  cloud:
    nacos:
      server-addr: localhost:8848 # nacos 服务地址

服务集群属性

1、修改 application.yml

spring:
  cloud:
    nacos:
      server-addr: localhost:8848 # nacos 服务地址
      discovery:
        cluster-name: SX # 配置集群名称,也就是机房位置

Nacos 服务分级存储模型

  • 一级是服务,例如 userservice
  • 二级是集群,例如山西或山东
  • 三级是实例,例如山西机房的某台部署了 userservice 的服务器

根据集群负载均衡

先将 order-service 设置集群名称

设置负载均衡的 IRule 为 NacosRule,这个规则优先会寻找与自己同集群的服务

userservice:
  ribbon:
    NFLoadBalancerRuleClassName: com.alibaba.cloud.nacos.ribbon.NacosRule # 负载均衡规则
实际部署中会出现这样的场景
  • 服务器设备性能有差异,部分实例所在集器性能比较好,另一些较差,我们希望性能好的集器承担更多的用户请求

Nacos 提供了权重配置来控制访问频率,权重越大则访问频率越高

环境隔离 - namespace

Nacos 中服务存储和数据存储的最外层都是一个名为 namespace 的东西,用来做最外层隔离

1、在 Nacos 控制台可以创建 namespace,用来隔离不同环境

2、填写写的命名空间信息(命名空间名 dev、描述 开发环境)

3、xml 配置 namespace(命名空间 ID)

    nacos:
      server-addr: localhost:8848
      discovery:
        cluster-name: SX # 配置集群名称,也就是机房位置
        namespace: 36cd6f37-dc38-4c0a-b89d-080fe1ed18dd # dev 环境
  • namespace 用来做环境隔离
  • 每个 namespace 都有唯一 id
  • 不同 namespace 下的服务不可见

临时实例和非临时实例ya

服务注册到 Nacos 时,可以选择注册为临时或非临时实例

spring:
  cloud:
    nacos:
      discovery:
        ephemeral: false # 设置非临时实例

Nacos 与 eureka

共同点:

  • 都支持服务注册和服务拉取
  • 都支持服务提供者心跳方式做健康检测

区别:

  • Nacos 支持服务端制动检测提供者状态:临时实例采用心跳模式,非临时实例采用主动检测模式
  • 临时实例心跳不正常会被剔除,非临时实例则不会被剔除
  • Nacos 支持服务列表变更的消息推送模式,服务列表更新更及时
  • Nacos 集群默认采用 AP 方式,当集群中存在非临时实例时,采用 CP 模式;Eureka 采用 AP 方式

Nacos 配置管理

统一配置管理

配置更改热更新

在 nacos 中添加配置信息(配置列表)

在弹出的表单中填写配置信息:

  • 配置文件的 id:[服务名称]-[profile]_[后缀名(yaml)]
  • 分组,默认
  • 格式,支持 yaml 和 properties
  • 发布

配置获取步骤:

项目启动 -》(在 bootstrap.yml 中获取 nacos 地址)读取 nacos 中配置文件 -》读取本地配置文件 application.yml -》创建 spring 容器 -》加载 bean

1、引入 Nacos 的配置管理客户端依赖

<!-- nacos 的配置管理依赖 -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>

2、在 resource 中添加 bootstrap.yml 文件,这个文件时引导文件,优先级高于 application.yml

配置 nacos 地址、当前环境、服务名称、文件后缀名,这些决定了程序启动时去 nacos 读取哪个文件

spring:
  application:
    name: userservice
  profiles:
    active: dev # 环境
  cloud:
    nacos:
      server-addr: localhost:8848 # nacos 地址
      config:
        file-extension: yaml # 文件后缀名

3、测试 controller

@Value("${pattern.dateformat}")
private String dateformat;

@GetMapping("now")
public String now(){
    return LocalDateTime.now().format(DateTimeFormatter.ofPattern(dateformat));
}

配置自动刷新

Nacos 中的配置文件变更后,微服务无需重启就可以感知。不过需要通过下面两种配置实现:

  • 方式一:在 @Value 注入的变量所在类上添加 @RefreshScope
  • 方法二:使用 @ConfigurationProperties 注解
@Data
@Component
@ConfigurationProperties(prefix = "pattern")
public class PattenProperties {
    private String dateformat;
}

多环境配置共享

微服务启动时会从 nacos 读取多个配置文件:

  • [spring.application.name]-[spring.prorfiles.active].yaml([服务名]-[spring.prorfiles.active].yaml,环境配置)
  • [spring.application.name].yaml ([服务名].yaml,默认配置,多环境共享)

无论 profile 如何变化,[spring.application.name].yaml 这个文件一定会加载,因此多环境共享配置可以写入这个文件

多配置的优先级:

[服务名]-[环境].yaml > [服务名].yaml > 本地配置

Nacos 集群搭建

搭建步骤

  • 搭建 M有SQL 集群并初始化数据库表
  • 下载解压 nacos
  • 修改集群配置(节点信息)、数据库配置
  • 分别启动多个 nacos 节点
  • nginx 反向代理

http 客户端 Feign

RestTemplate 方法调用存在的问题

  • 代码可读性差,编程体验不统一
  • 参数复杂 URL 难以维护

Feign

Feign 是一个声明式的 http 客户端

其作用就是帮助我们优雅的实现 http 请求的发送,解决上面提到的问题

定义和使用 Feign 客户端

1、引入依赖

<!-- feign 客户端依赖 -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

2、在启动类添加注解开启 Feign 的功能

@MapperScan("cn.itcast.order.mapper")
@SpringBootApplication
@EnableFeignClients
public class OrderApplication {

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

3、编写 Feign 客户端

@FeignClient("userservice")
public interface UserClient {

    @GetMapping("/user/{id}")
    User findById(@PathVariable("id") Long id);
}

主要是基于 Spring MVC 的注解来声明远程调用的信息

  • 服务名称:userservice
  • 请求方式:GET
  • 请求路径:/user/{id}
  • 请求参数:Long id
  • 返回值类型:User

4、用 Feign 客户端代替 RestTemplate

@Autowired
private UserClient userClient;

public Order queryOrderById(Long orderId) {
    // 1.查询订单
    Order order = orderMapper.findById(orderId);
    // 2.利用 Feign 远程调用
    User user = userClient.findById(order.getUserId());
    // 3.封装 user 到 order
    order.setUser(user);
    // 4.返回
    return order;
}

自定义 Feign 的配置

Feign 运行自定义配置来覆盖默认配置

类型作用说明
feign.Logger.Level修改日志级别包含四种不同的级别:NONE、BASIC、HEADERS、FULL
feign.codec.Decoder响应结果的解析器http 远程调用的结果做解析,例如解析 json 字符串为 java 对象
feign.codec.Encoder请求参数编码请求参数编码,便于通过 http 请求发送
feign.Contract支持的注解格式默认是 Spring MVC 的注解
feign.Retryer失败重试机制请求失败的重试机制,默认是没有,不过会使用 Ribbon 的重试

一般我们需要配置的就是日志级别

配置 Feign 日志有两种方式

方式一:配置文件方式

  • 全局生效:
feign:
  client:
    config:
      default: # 这里用 default 就是全局配置,如果写服务名称,则是针对某个微服务的配置
        loggerLevel: FULL # 日志级别
  • 局部生效:
feign:
  client:
    config:
      userservice: # 针对 userservice 的配置
        loggerLevel: FULL # 日志级别

方式二:java 代码方式

先声明一个 Bean:

public class DefaultFeignConfiguration {
    @Bean
    public Logger.Level logLevel(){
        return Logger.Level.BASIC;
    }
}

而后如果是全局配置,则把它放到 @EnableFeignClients 这个注解中:

@EnableFeignClients(defaultConfiguration = DefaultFeignConfiguration.class)

如果是局部配置,则把它放到 @FeignClient 这个注解中:

@FeignClient("userservice", configuration = DefaultFeignConfiguration.class)

Feign 的性能优化

Feign 底层的客户端实现:

  • URLConnection:默认实现,不支持连接池
  • Apache HttpClient:支持连接池
  • OKHttp:支持连接池

因此优化 Feign 的性能主要包括:

  • 使用连接池代替默认的 URLConnection
  • 日志级别,最好用 basic 或 none
Feign 的性能优化-连接池配置

Feign 添加 HttpClient 的支持:

引入依赖:

<!-- httpClient 的依赖 -->
<dependency>
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-httpclient</artifactId>
</dependency>

配置连接池:

feign:
  httpclient:
    enabled: true # 支持 httpClient 的开关
    max-connections: 200 # 最大连接数
    max-connections-per-route: 50 # 单个路径的最大连接数

根据压测调试最大连接数和单个路径的最大连接数的最佳值

Feign 的最佳实践

方式一(继承):给消费者的 FeignClient 和提供者的 controller 定义统一的父接口作为标准。

  • 服务紧耦合
  • 父几口参数列表中的映射不会被继承

方式二(抽取):将 FeignClient 抽取为独立模块,并且把接口有关的 POJO、默认的 Feign 配置都放到这个模块中,提供给所有消费者使用

实现步骤:

1、创建一个 module,命名为 feign-api,然后引入 feign 的 starter 依赖

2、将 order-service 中编写的 UserClient、User、DefaultFeignConfiguration 都复制到 feign-api 项目中

3、在 order-service 中引入 feign-api 的依赖

4、修改 order-service 中的所有与上述三个组件有关的 import 部分,改成导入 feign-api 中的包

5、重启测试

当定义的 FeignClien 不在 SpringBootApplication 的扫描包范围时,这些 FeignClient 无法使用。有两种方式解决:

方式一:指定 FeignClient 所在包

@EnableFeignClients(basePackages = "cn.itcast.feign.clients")

方式二:指定 FeignClient 字节码

@EnableFeignClients(clients = {UserClient.class})

统一网关 Gateway

网关功能:

  • 身份认证和权限校验
  • 服务路由、负载均衡
  • 请求限流

在 Spirng Cloud 中网关的实现包括两种:

  • gateway
  • zuul

Zuul 时基于 Servlet 的实现,属于阻塞式编程。而 SpringCloud Gateway 则是基于 Spring5 中提供的 WebFlux,属于响应式编程的实现,具有更好的性能。

搭建网关服务

1、创建新的 module,引入 Spring Cloud Gateway 的依赖和 nacos 的服务发现依赖:

<!-- nacos 服务注册发现依赖 -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- 网关 gateway 依赖 -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>

2、编写路由配置及 nacos 地址

server:
  port: 10010
spring:
  application:
    name: gateway
  cloud:
    nacos:
      server-addr: localhost:8848 # nacos 地址
    gateway:
      routes:
        - id: user-service # 路由标识,必须唯一
          uri: lb://userservice # 路由的目标地址,lb 是 loadBalance 简写 负载均衡,后面跟服务名称
          predicates: # 路由断言,判断请求是否符合规则
            - Path=/user/** # 路径断言,判断路径是否以/user开头,如果是则符合
        - id: order-service
          uri: lb://orderservice
          predicates:
            - Path=/order/**

最好不要复制,容易出错

路由配置包括:

  • 路由 id:路由的唯一标识
  • 路由目标(uri):路由的目标地址,http 代表固定地址,lb 代表根据服务名负载均衡
  • 路由断言(predicates):判断路由的规则
  • 路由过滤器(filters):对请求或响应做处理

路由断言工厂 Route Predicate Factory

  • 我们在配置文件中写的断言规则只是字符串,这些字符串会被 Predicate Factory 读取并处理,转变为路由判断的条件

  • 例如 Path=/user/** 是按照路径匹配,这个规则是由 org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory 类来处理的

  • 像这样的断言工厂在 Spring Cloud Gateway 还有十几个

Spring 提供的 11 种基本的 Predicate 工厂:

名称说明示例
After是某个时间点后的请求
Before是某个时间点之前的请求
Between是某两个时间点之前的请求
Cookie请求必须包含某些 cookie
Header请求必须包含某些 header
Host请求必须是访问某个 host(域名)
Method请求方式必须是指定方式
Path请求路径必须符合指定规则
Query请求参数必须包含指定参数
RemoteAddr请求者的 ip 必须是指定范围
Weight权重处理

路由过滤器 GatewayFilter

GatewayFilter 是网关种提供的一种过滤器,可以对进入网关的请求和微服务返回的响应做处理

过滤器工厂 GatewayFilterFactory

Spring 提供了 31 种不同的路由过滤器工厂

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

给所有进入 userservice 的请求添加一个请求头:Truth=whz is freaking awesome!

实现方式:在 gateway 中修改 application.yml 文件,给 userservice 的路由添加过滤器:

spring:
  cloud:
    gateway:
      routes:
        - id: user-service 
          uri: lb://userservice 
          predicates: 
            - Path=/user/** 
          filters:
            - AddRequestHeader=Truth,whz is freaking aowsome!

如果要对所有的路由都生效,则可以将过滤器工厂写到 default 下

spring:
  cloud:
    gateway:
      routes:
        - id: user-service 
          uri: lb://userservice 
          predicates: 
            - Path=/user/** 
        - id: order-service
          uri: lb://orderservice
          predicates:
            - Path=/order/**
      default-filters:
        - AddRequestHeader=Truth,whz is freaking aowsome!

全局过滤器 GlobalFilter

全局过滤器的作用也是处理一切进入网关的请求和微服务响应,与 GatewayFilter 的作用一样。

区别在于 GatewayFilter 通过配置定义,处理逻辑是固定的。而 GlobalFilter 的逻辑需要自己写代码实现。

定义方式是实现 GlobaFilter 接口

定义全局过滤器,拦截并判断用户身份

  • 参数中是否有 authorization
  • authorization 参数值是否为 admin

如果同时满足则放行,否则拦截

//@Order(-1) //权重 越小越早执行
@Component
public class AuthorizeFilter implements GlobalFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //1、获取请求参数
        ServerHttpRequest request = exchange.getRequest();
        MultiValueMap<String, String> params = request.getQueryParams();
        //2、获取参数中的 authorization 参数
        String auth = params.getFirst("authorization");
        //3、判断参数值是否等于 admin
        if ("admin".equals(auth)) {
            //4、是,放行
            return chain.filter(exchange);
        }
        //5、否,拦截
        //5.1、设置状态码
        exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
        //5.2、拦截请求
        return exchange.getResponse().setComplete();
    }

    @Override
    public int getOrder() {
        return -1;
    }
}

过滤器执行顺序

请求进入网关会碰到三类过滤器:当前路由的过滤器、DefaultFilter、GlobalFilter

请求路由后,会将当前路由过滤器和 DefaultFilter、GlobalFilter,合并到一个过滤器链(集合)中,排序后一次执行每个过滤器

  • 每一个过滤器都必须指定一个 int 类型的 order 值,order 值越小,优先级越高,执行顺序越靠前

  • GlobalFilter 通过实现 Ordered 接口,或者添加 @Order 注解来指定 order 值,由我们自己指定

  • 路由过滤器和 defaultFilter 的 order 由 Spring 指定,默认是按照声明顺序从 1 递增

  • 当过滤器的 order 值一样时,会按照 defaultFilter > 路由过滤器 > GlobalFilter 的顺序执行(defaultFilter最先,然后是局部的路由过滤器,最后是全局过滤器)

跨域问题处理

跨域:域名不一致就是跨域

  • 域名不同
  • 域名相同,端口不同

跨域问题:浏览器禁止请求的发起者与服务端发生跨域 ajax 请求,,请求被浏览器拦截的问题

解决方案:CORS

网关处理跨域采用的同样是 CORS 方案,并且只需要简单配置即可实现:

spring:
  cloud:
    gateway:
      globalcors: # 全局的跨域处理
        add-to-simple-url-handler-mapping: true # 解决 options 请求被拦截问题
        corsConfigurations:
        '[/**]':
          allowedOrigins: # 允许哪些网站的跨域请求
            - "http://localhost:8090"
            - "http://www.leyou.com"
          allowedMethods: # 允许的跨域 ajax 的请求方式
            - "GET"
            - "POST"
            - "DELETE"
            - "PUT"
            - "OPTIONS"
          allowedHeaders: "*" # 允许在请求中携带的头信息
          allowCredentials: true # 是否允许携带 cookie
          maxAge: 360000 # 这次跨域检测的有效期
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值