框架阶段六:SpringCloud
🧑🎓 个人主页:花棉袄
📖 本章内容:【框架阶段六:SpringCloudSpringCloud】📺学习视频推荐📝文档
✍🏻 版权: 本文由【花棉袄】原创💝在CSDN首发💝需要转载请联系博主
🧑🏻🦰服务架构
💟 单体架构:简单方便,高度耦合,扩展性差,适合小型项目。例如:学生管理系统
💟 分布式架构:松耦合,扩展性好,但架构复杂,难度大。适合大型互联网项目,例如:京东、淘宝
💟 微服务:一种良好的分布式架构方案
💮 优点:拆分粒度更小、服务更独立、耦合度更低
💮 缺点:架构非常复杂,运维、监控、部署难度提高
💮 SpringCloud是微服务架构的一站式解决方案,集成了各种优秀微服务功能组件
1️⃣单体架构
💟 单体架构:将业务的所有功能集中在一个项目中开发,打成一个包部署
💮 优点:架构简单,部署成本低
💮 缺点:高度耦合,扩展性差
2️⃣分布式架构
💟 分布式架构:根据业务功能对系统做拆分,每个业务功能模块作为独立项目开发,称为一个服务
💮 优点:降低服务耦合,有利于服务升级和拓展
💮 缺点:服务调用关系错综复杂
3️⃣微服务架构
💟 微服务的架构特征
💮单一职责
:微服务拆分粒度更小,每一个服务都对应唯一的业务能力
💮自治
:团队独立、技术独立、数据独立,独立部署和交付
💮面向服务
:服务提供统一标准的接口,与语言和技术无关
💮隔离性强
:服务调用做好隔离、容错、降级,避免出现级联问题
🔴微服务是一种经过良好架构设计的分布式架构方案
4️⃣微服务技术对比
👨🏻🦱服务拆分
1️⃣服务拆分
💟 服务拆分原则
💮 不同微服务,不要重复开发相同业务
💮 微服务数据独立,不要访问其它微服务的数据库
💮 微服务可以将自己的业务暴露为接口,供其它微服务调用
2️⃣远程调用
💟 注册RestTemplate
@Configuration
public class MyConfig {
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
💟 实现远程调用
@Service
public class OrderService {
@Autowired
private OrderMapper orderMapper;
@Autowired
private RestTemplate restTemplate;
public Order queryOrderById(Long orderId) {
// 1.查询订单
Order order = orderMapper.findById(orderId);
String url = "http://localhost:8081/user/" + order.getUserId();
User user = restTemplate.getForObject(url, User.class);
order.setUser(user);
// 4.返回
return order;
}
}
💟 查询订单的同时查询用户信息
{
"id": 101,
"price": 699900,
"name": "Apple 苹果 iPhone 12 ",
"num": 1,
"userId": 1,
"user": {
"id": 1,
"username": "柳岩",
"address": "湖南省衡阳市"
}
}
3️⃣提供者与消费者
💟 服务提供者:一次业务中,被其它微服务调用的服务(提供接口给其它微服务)
💟 服务消费者:一次业务中,调用其它微服务的服务(调用其它微服务提供的接口)
👩🏻🦲Eureka注册中心
1️⃣Eureka作用
💟 Eureka作用
💟 消费者如何获取服务提供者具体信息
💮 服务提供者启动时向Eureka注册自己的信息
💮 Eureka保存服务名称到服务实例地址列表的映射关系
💮 消费者根据服务名称向Eureka拉取提供者信息
💟 如果有多个服务提供者,消费者该如何选择
💮 消费者利用负载均衡,从实例列表中选中一个实例地址
💮 向该实例地址发起远程调用
💟 消费者如何感知服务提供者健康状态
💮 服务提供者会每隔一段时间(默认30秒)向注册中心发起心跳请求,报告健康状态
💮 eureka会更新记录服务列表信息,将心跳不正常的实例从服务列表中剔除
💮 消费者就会拉取到最新的信息
2️⃣搭建注册中心
- 首先大家注册中心服务端:eureka-server,这必须是一个
独立的微服务
1️⃣添加依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
- SpringCloud依赖版本库,引入SpringCloud组件时不需要指定版本信息
<!-- springCloud -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Hoxton.SR10</version>
<type>pom</type>
<scope>import</scope>
</dependency>
2️⃣ 开启eureka的注册中心功能
- 添加一个@EnableEurekaServer注解,开启eureka的注册中心功能
@SpringBootApplication
@EnableEurekaServer
public class EurekaApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaApplication.class, args);
}
}
3️⃣ 配置文件
server:
port: 10086
spring:
application:
name: eureka-server
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:10086/eureka
- 启动微服务,然后在浏览器访问:http://127.0.0.1:10086
3️⃣服务注册
1️⃣ 添加依赖
- 在服务提供者的pom文件中,引入下面的eureka-client依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
2️⃣ 配置文件
spring:
application:
name: userservice
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:10086/eureka
- 访问
http://127.0.0.1:10086
4️⃣服务发现
1️⃣ 添加依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
2️⃣ 配置文件
spring:
application:
name: orderservice
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:10086/eureka
3️⃣ 服务拉取
- eureka-server中拉取user-service服务的实例列表,并且实现负载均衡
@Configuration
public class MyConfig {
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
- 修改访问的url路径,用服务名代替(ip和端口)
@Service
public class OrderService {
@Autowired
private OrderMapper orderMapper;
@Autowired
private RestTemplate restTemplate;
public Order queryOrderById(Long orderId) {
// 1.查询订单
Order order = orderMapper.findById(orderId);
String url = "http://userservice/user/" + order.getUserId();
User user = restTemplate.getForObject(url, User.class);
order.setUser(user);
// 4.返回
return order;
}
}
👨🏻🦳Ribbon负载均衡
1️⃣负载均衡原理
💟 负载均衡原理
💮 SpringCloud底层是利用了Ribbon的组件,来实现负载均衡功能的
💟 为什么我们只输入了service名称就可以访问了呢?
💮LoadBalancerInterceptor
,这个类会在对RestTemplate的请求进行拦截
💮 从Eureka注册中心根据服务名获取服务列表,随后利用负载均衡算法得到真实的服务地址信息,服务名替换成获取ip和端口
💟 基本流程
💮 拦截我们的RestTemplate请求http://userservice/user/1
💮 RibbonLoadBalancerClient会从请求url中获取服务名称,也就是user-service
💮 DynamicServerListLoadBalancer根据user-service到eureka拉取服务列表
💮 eureka返回列表,localhost:8081、localhost:8082
💮 IRule利用内置负载均衡规则,从列表中选择一个,例如localhost:8081
💮 RibbonLoadBalancerClient修改请求地址,用localhost:8081替代userservice,得到http://localhost:8081/user/1
发起真实请求
2️⃣负载均衡策略
内置负载均衡规则类 | 规则描述 |
---|---|
RoundRobinRule | 简单轮询服务列表来选择服务器。它是Ribbon默认的负载均衡规则。 |
AvailabilityFilteringRule | 对以下两种服务器进行忽略: (1)在默认情况下,这台服务器如果3次连接失败,这台服务器就会被设置为“短路”状态。短路状态将持续30秒,如果再次连接失败,短路的持续时间就会几何级地增加。 (2)并发数过高的服务器。如果一个服务器的并发连接数过高,配置了AvailabilityFilteringRule规则的客户端也会将其忽略。并发连接数的上限,可以由客户端的..ActiveConnectionsLimit属性进行配置。 |
WeightedResponseTimeRule | 为每一个服务器赋予一个权重值。服务器响应时间越长,这个服务器的权重就越小。这个规则会随机选择服务器,这个权重值会影响服务器的选择。 |
ZoneAvoidanceRule | 以区域可用的服务器为基础进行服务器的选择。使用Zone对服务器进行分类,这个Zone可以理解为一个机房、一个机架等。而后再对Zone内的多个服务做轮询。 |
BestAvailableRule | 忽略那些短路的服务器,并选择并发数较低的服务器。 |
RandomRule | 随机选择一个可用的服务器。 |
RetryRule | 重试机制的选择逻辑 |
- 默认的实现就是ZoneAvoidanceRule,是一种轮询方案
3️⃣自定义负载均衡策略
1️⃣ 通过配置类自定义负载均衡策略
@Bean
public IRule randomRule(){
return new RandomRule();
}
2️⃣ 通过配置文件配置文件方式
# 给某个微服务配置负载均衡规则,这里是userservice服务
userservice:
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule # 负载均衡规则
4️⃣饥饿加载
💟 Ribbon默认是采用懒加载:即第一次访问时才会去创建LoadBalanceClient,请求时间会很长
💟 而饥饿加载则会在项目启动时创建,降低第一次访问的耗时,通过下面配置开启饥饿加载
ribbon:
eager-load:
enabled: true # 开启饥饿加载
clients: # 指定饥饿加载的服务名称
- userservice
👩🏻🦳Nacos注册中心
1️⃣服务注册
1️⃣ 添加依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
- 父工程引入SpringCloudAlibaba的依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2.2.6.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
2️⃣ 配置Nacos地址
spring:
application:
name: userservice
cloud:
nacos:
discovery:
server-addr: 49.235.106.124:8848
2️⃣服务发现
1️⃣ 添加依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
2️⃣ 配置Nacos地址
spring:
application:
name: orderservice
cloud:
nacos:
discovery:
server-addr: 49.235.106.124:8848
3️⃣ 服务拉取
- eureka-server中拉取user-service服务的实例列表,并且实现负载均衡
@Configuration
public class MyConfig {
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
- 修改访问的url路径,用服务名代替(ip和端口)
@Service
public class OrderService {
@Autowired
private OrderMapper orderMapper;
@Autowired
private RestTemplate restTemplate;
public Order queryOrderById(Long orderId) {
// 1.查询订单
Order order = orderMapper.findById(orderId);
String url = "http://userservice/user/" + order.getUserId();
User user = restTemplate.getForObject(url, User.class);
order.setUser(user);
// 4.返回
return order;
}
}
👳🏻♀️Nacos负载均衡
1️⃣配置集群
- 同集群优先的负载均衡
spring:
application:
name: orderserver
cloud:
nacos:
discovery:
server-addr: 49.235.106.124:8848
cluster-name: SH # 集群名称
- 修改负载均衡规则
userservice:
ribbon:
NFLoadBalancerRuleClassName: com.alibaba.cloud.nacos.ribbon.NacosRule # 负载均衡规则
2️⃣权重配置
💟 Nacos提供了权重配置来控制访问频率,权重越大则访问频率越高
💟 注意:如果权重修改为0,则该实例永远不会被访问
3️⃣环境隔离
💟 Nacos提供了namespace来实现环境隔离功能
💮 nacos中可以有多个namespace
💮 namespace下可以有group、service等
💮 不同namespace之间相互隔离,例如不同namespace的服务互相不可见
spring:
application:
name: orderserver
cloud:
nacos:
discovery:
server-addr: localhost:8848
cluster-name: HZ
namespace: 6c4e9d1a-f6de-4f77-9c36-d4c112831b1a # 命名空间,填ID
🧔🏻♀️Nacos服务实例
1️⃣Nacos服务实例
💟 Nacos的服务实例分为两种类型
💮 临时实例:如果实例宕机超过一定时间,会从服务列表剔除,默认的类型
💮 非临时实例:如果实例宕机,不会从服务列表剔除,也可以叫永久实例
💟 配置一个服务实例为永久实例
spring:
cloud:
nacos:
discovery:
ephemeral: false # 设置为非临时实例
2️⃣Nacos与Eureka的区别
💟 Nacos与eureka的共同点
💮 都支持服务注册和服务拉取
💮 都支持服务提供者心跳方式做健康检测
💟 Nacos与Eureka的区别
💮 Nacos支持服务端主动检测提供者状态:临时实例采用心跳模式,非临时实例采用主动检测模式
💮 临时实例心跳不正常会被剔除,非临时实例则不会被剔除
💮 Nacos支持服务列表变更的消息推送模式,服务列表更新更及时
💮 Nacos集群默认采用AP方式,当集群中存在非临时实例时,采用CP模式;Eureka采用AP方式
🤶🏻Nacos配置管理
1️⃣统一配置管理
1️⃣ 添加依赖
<!--nacos配置管理依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
2️⃣ 添加bootstrap.yaml
spring:
application:
name: userservice # 服务名称
profiles:
active: dev #开发环境,这里是dev
cloud:
nacos:
server-addr: localhost:8848 # Nacos地址
config:
file-extension: yaml # 文件后缀名
3️⃣ 读取nacos配置
@Slf4j
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
@Value("${pattern.dateformat}")
private String dateformat;
@GetMapping("now")
public String now(){
return LocalDateTime.now().format(DateTimeFormatter.ofPattern(dateformat));
}
}
2️⃣配置热更新
💟 方式一
💮 在@Value注入的变量所在类上添加注解@RefreshScope
@Slf4j
@RefreshScope
@RestController
@RequestMapping("/user")
public class UserController {
}
💟 方式二
💮 使用@ConfigurationProperties注解代替@Value注解
@Component
@Data
@ConfigurationProperties(prefix = "pattern")
public class PatternProperties {
private String dateformat;
}
- 使用配置类
@Autowired
private PatternProperties patternProperties;
3️⃣多环境配置共享
💟 配置共享的优先级
1️⃣ 服务名-profile.yaml
2️⃣ 服务名.yaml
3️⃣ 本地配置
🧑🏻🦲Feign远程调用
1️⃣Feign远程调用
1️⃣ 添加依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
2️⃣ 开启Feign的功能
💮 消费者的启动类添加注解开启Feign的功能
@MapperScan("cn.itcast.order.mapper")
@SpringBootApplication
@EnableFeignClients
public class OrderApplication {
public static void main(String[] args) {
SpringApplication.run(UserApplication.class, args);
}
}
3️⃣ Feign的客户端
@FeignClient("userservice")
public interface UserClient {
@GetMapping("/user/{id}")
User findById(@PathVariable("id") Long id);
}
- 服务名称:userservice
- 请求方式:GET
- 请求路径:/user/{id}
- 请求参数:Long id
- 返回值类型:User
4️⃣ 使用FeignClient中定义的方法代替RestTemplate
@Service
public class OrderService {
@Autowired
private OrderMapper orderMapper;
@Autowired
private UserClient userClient;
public Order queryOrderById(Long orderId) {
// 1.查询订单
Order order = orderMapper.findById(orderId);
User user = userClient.findById(order.getUserId());
order.setUser(user);
// 4.返回
return order;
}
}
2️⃣自定义配置
feign.Logger.Level | 修改日志级别 | 包含四种不同的级别:NONE、BASIC、HEADERS、FULL |
---|---|---|
feign.codec.Decoder | 响应结果的解析器 | http远程调用的结果做解析,例如解析json字符串为java对象 |
feign.codec.Encoder | 请求参数编码 | 将请求参数编码,便于通过http请求发送 |
feign. Contract | 支持的注解格式 | 默认是SpringMVC的注解 |
feign. Retryer | 失败重试机制 | 请求失败的重试机制,默认是没有,不过会使用Ribbon的重试 |
- 自定义时,只需要创建自定义的@Bean覆盖默认Bean即可
3️⃣日志级别
💟 NONE:不记录任何日志信息,这是默认值
💟 BASIC:仅记录请求的方法,URL以及响应状态码和执行时间
💟 HEADERS:在BASIC的基础上,额外记录了请求和响应的头信息
💟 FULL:记录所有请求和响应的明细,包括头信息、请求体、元数据
1️⃣ 配置文件方式
- 基于配置文件修改feign的日志级别针对单个服务
feign:
client:
config:
userservice: # 针对某个微服务的配置
loggerLevel: FULL # 日志级别
- 也可以针对所有服务
feign:
client:
config:
default: # 这里用default就是全局配置,如果是写服务名称,则是针对某个微服务的配置
loggerLevel: FULL # 日志级别
2️⃣ Java代码方式
public class DefaultFeignConfiguration {
@Bean
public Logger.Level feignLogLevel(){
return Logger.Level.BASIC; // 日志级别为BASIC
}
}
- 如果要全局生效,将其放到启动类的
@EnableFeignClients
注解中
@EnableFeignClients(defaultConfiguration = DefaultFeignConfiguration .class)
- 如果是局部生效,则把它放到对应的
@FeignClient
注解中
@FeignClient(value = "userservice", configuration = DefaultFeignConfiguration .class)
4️⃣Feign性能优化
- 提高Feign的性能主要手段就是使用连接池 代替默认的 URLConnection
1️⃣ 添加依赖
<!--httpClient的依赖 -->
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-httpclient</artifactId>
</dependency>
2️⃣ 开启连接池
feign:
client:
config:
default: # default全局的配置
loggerLevel: BASIC # 日志级别,BASIC就是基本的请求和响应信息
httpclient:
enabled: true # 开启feign对HttpClient的支持
max-connections: 200 # 最大的连接数
max-connections-per-route: 50 # 每个路径的最大连接数
👳🏻♂️Gateway服务网关
网关的****:
1️⃣核心功能特性
1️⃣ 权限控制:网关作为微服务入口,需要校验用户是是否有请求资格,如果没有则进行拦截
2️⃣ 路由和负载均衡:一切请求都必须先经过gateway,但网关不处理业务,而是根据某种规则,把请求转发到某个微服务,这个过程叫做路由。当然路由的目标服务有多个时,还需要做负载均衡
3️⃣ 限流:当请求流量过高时,在网关中按照下流的微服务能够接受的速度来放行请求,避免服务压力过大
2️⃣搭建网关服务
1️⃣ 添加依赖
<!--网关-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!--nacos服务发现依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
2️⃣ 启动类
@SpringBootApplication
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class, args);
}
}
3️⃣ 配置文件
server:
port: 10010 # 网关端口
spring:
application:
name: gateway # 服务名称
cloud:
nacos:
server-addr: localhost:8848 # nacos地址
gateway:
routes: # 网关路由配置
- id: user-service # 路由id,自定义,只要唯一即可
# uri: http://127.0.0.1:8081 # 路由的目标地址 http就是固定地址
uri: lb://userservice # 路由的目标地址 lb就是负载均衡,后面跟服务名称
predicates: # 路由断言,也就是判断请求是否符合路由规则的条件
- Path=/user/** # 这个是按照路径匹配,只要以/user/开头就符合要求
💟 路由配置包括
💮 路由id:路由的唯一标示
💮 路由目标(uri):路由的目标地址,http代表固定地址,lb代表根据服务名负载均衡
💮 路由断言(predicates):判断路由的规则
💮 路由过滤器(filters):对请求或响应做处理
- 将
/user/**
开头的请求,代理到lb://userservice
,lb是负载均衡,根据服务名拉取服务列表,实现负载均衡
3️⃣断言工厂
** | 说明 | 示例 |
---|---|---|
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, Jack或者- Query=name |
RemoteAddr | 请求者的ip必须是指定范围 | - RemoteAddr=192.168.1.1/24 |
Weight | 权重处理 |
- 例如Path=/user/**是按照路径匹配
4️⃣过滤器工厂
- GatewayFilter是网关中提供的一种过滤器,可以对进入网关的请求和微服务返回的响应做处理
💟 过滤器的作用是什么?
💮 对路由的请求或响应做加工处理,比如添加请求头
💮 配置在路由下的过滤器只对当前路由的请求生效
💟 路由过滤器的种类
名称 | 说明 |
---|---|
AddRequestHeader | 给当前请求添加一个请求头 |
RemoveRequestHeader | 移除请求中的一个请求头 |
AddResponseHeader | 给响应结果中添加一个响应头 |
RemoveResponseHeader | 从响应结果中移除有一个响应头 |
RequestRateLimiter | 限制请求的流量 |
spring:
cloud:
gateway:
routes:
- id: user-service
uri: lb://userservice
predicates:
- Path=/user/**
filters: # 过滤器
- AddRequestHeader=Truth, Itcast is freaking awesome! # 添加请求头
5️⃣默认过滤器
- 如果要对所有的路由都生效,则可以将过滤器工厂写到default下
spring:
cloud:
gateway:
routes:
- id: user-service
uri: lb://userservice
predicates:
- Path=/user/**
default-filters: # 默认过滤项
- AddRequestHeader=Truth, Itcast is freaking awesome!
5️⃣全局过滤器
💟 全局过滤器的作用也是处理一切进入网关的请求和微服务响应,与GatewayFilter的作用一样
💟 区别在于GatewayFilter通过配置定义,处理逻辑是固定的
💟 而GlobalFilter的逻辑需要自己写代码实现
💟 在filter中编写自定义逻辑,可以实现下列功能
💮 登录状态判断
💮 权限校验
💮 请求限流等
6️⃣自定义全局过滤器
- 参数中是否有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;
}
}
7️⃣过滤器执行顺序
💟 请求进入网关会碰到三类过滤器
1️⃣ 当前路由的过滤器
2️⃣ DefaultFilter
3️⃣ GlobalFilter
- 请求路由后,会将当前路由过滤器和DefaultFilter、GlobalFilter,合并到一个过滤器链(集合)中,排序后依次执行每个过滤器
8️⃣排序的规则
💟 配置排序的规则
💮 GlobalFilter通过实现Ordered接口
💮 添加@Order注解来指定order值
💟 每一个过滤器都必须指定一个int类型的order值,order值越小,优先级越高,执行顺序越靠前
💟 GlobalFilter通过实现Ordered接口,或者添加@Order注解来指定order值,由我们自己指定
💟 路由过滤器和defaultFilter的order由Spring指定,默认是按照声明顺序从1递增。
💟 当过滤器的order值一样时,会按照 defaultFilter > 当前路由过滤器 > GlobalFilter 的顺序执行
🤴🏻跨域问题
1️⃣跨域问题
💟 跨域:域名不一致就是跨域
💮域名不同
: www.taobao.com 和 www.taobao.org 和 www.jd.com 和 miaosha.jd.com
💮域名相同 端口不同
:localhost:8080和localhost8081
💟
跨域问题
:浏览器禁止请求的发起者与服务端发生跨域ajax请求
,请求被浏览器拦截的问题
2️⃣解决跨域问题
1️⃣方式一:配置类
@Configuration
public class FireFlyMallCorsConfiguration {
@Bean // 添加过滤器
public CorsWebFilter corsWebFilter(){
// 基于url跨域,选择reactive包下的
UrlBasedCorsConfigurationSource source=new UrlBasedCorsConfigurationSource();
// 跨域配置信息
CorsConfiguration corsConfiguration = new CorsConfiguration();
// 允许跨域的头
corsConfiguration.addAllowedHeader("*");
// 允许跨域的请求方式
corsConfiguration.addAllowedMethod("*");
// 允许跨域的请求来源
corsConfiguration.addAllowedOrigin("*");
// 是否允许携带cookie跨域
corsConfiguration.setAllowCredentials(true);
// 任意url都要进行跨域配置
source.registerCorsConfiguration("/**",corsConfiguration);
return new CorsWebFilter(source);
}
}
2️⃣ 方式二:配置文件
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 # 这次跨域检测的有效期
📢💨如果文章对你有帮助【关注👍点赞❤️收藏⭐】
🏅 JAVA入门到飞起:《框架阶段》
🏅 第一阶段:📢💨 MyBatis
🏅 第二阶段:📢💨 Spring
🏅 第三阶段:📢💨 Spring MVC
🏅 第四阶段:📢💨 MyBatis PLUS
🏅 第五阶段:📢💨 SpringBoot2.0
🏅 第六阶段:📢💨 SpringCloud