SpringCloud学习笔记

embedded/2024/11/14 21:00:25/

SpringCloud

在微服务中,不同的服务板块是分开的,有自己的数据库。但是在业务中可能存在服务板块中互相调用的情况,比如订单服务中需要获取用户信息,这时候不能再自己的板块中直接进行查询,否则违反了微服务的理念,且如果数据库分开的话也无法实现查询,所以采取向其他服务发送请求的方式获取数据,在其他服务中调用相关的方法。要调用就需要在后端手动发送http请求。

如何在Java中发送http请求?

——利用RestTemplate,首先在启动类中利用bean注解注入对象,然后调用restTemplate的getForObject方法发送Get请求(其余类型的请求同理),参数为url,返回值类型为JSON。

一个服务既可以是提供者也可以是消费者

Eureka注册中心

Eureka出现要解决的问题

一个服务向另一个服务发送请求的时候需要url地址,但是url地址在不同的环境下比如生产环境、测试环境等是会变动的,且随着业务开发也可能会发生变更。如果在代码中写死后续就会难以维护。因此需要一个能够动态获取信息的方法。

Eureka注册中心在服务启动后,就会获取服务的信息,并保存下来。当消费者需要信息去访问提供者的时候就可以直接从Eureka中获取信息。

而提供者可能有多个,获取哪一个采用负载均衡算法。并且当服务在Eureka中注册后就会每隔30s向Eureka发送心跳,Eureka以此来确定服务是否存活,如果不存活信息就会被剔除。

记录服务信息心跳监控的是EurekaServer,服务提供者和消费者是EurekaClient。

Eureka实践

1.搭建注册中心

需要创建一个独立的微服务。

依赖:

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

然后编写启动类,其需要添加@EnableEurekaServer注解

并添加application.yml文件:

server:port: 10086 #服务端口
spring:application:name: eurekaserver #eureka的服务名称
eureka:client:service-url: #eureka的地址信息defaultZone: http://127.0.0.1:10086/eureka

注意:Eureka会将自己也注册,所以默认会有一个实例。

2.服务注册

第一步:引入依赖:

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

第二步:application.yml文件编写配置:

spring:application:name: userservice
eureka:client:service-url:defaultZone: http://127.0.0.1:10086/eureka

注意:需要作为EurekaClient的服务都需要注册。

测试需要启动两个实例,可以右键实例利用IDEA中的CopyConfiguration进行复制,然后修改端口避免冲突(编辑配置,在VM options中写入 -Dserver.port=8082)。启动后就可以在Eureka页面中看到一个服务的两个实例。

3.一个服务在Eureka中完成另外服务的拉取。

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

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

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

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

@LoadBalanced就是负载均衡的注解。

Ribbon负载均衡

在后端发送服务名替代ip的请求时,浏览器是无法识别的,需要有人对这个请求进行处理,也就是利用这个服务名取Eureka中获取服务的地址,并且还要实现负载均衡以最终选取一个地址使用。这个功能的实现者就是Ribbon。
在这里插入图片描述

当服务发送请求的时候,会被负载均衡拦截器LoadBalancerInterceptor拦截,拦截后交给RibbonLoadBalancerClient处理,它会获取其中的服务器名称,交给动态服务列表负载均衡器DynamicServerListLoadBalancer,其根据名称向eureka-server中获取到一个服务器列表,再根据IRule接口中的负载均衡的方法如轮询、随机等规则获取一个实例并返回给RibbonLoadBalancerClient,再进行地址的替换以得到真实地址。

IRule接口中的负载均衡策略实现
内置负载均衡规则类规则描述
RoundRobinRule简单轮询服务列表来选择服务器。
AvailabilityFilteringRule(1)在默认情况下,这台服务器如果3次连接失败,就会被设置为“短路”状态。短路状态将持续30s,如果再次连接失败,短路的持续时间会几何式增加。
(2)如果一个服务器的并发连接数过高,配置了AvailabilityFilteringRule规则的客户端也会将其忽略。
WeightedResponseTimeRule为每一个服务器赋予一个权重。服务器响应时间越长,这个服务器的权重就越小。这个规则会随机选择服务器,并根据权重值影响选择。
ZoneAvoidanceRule以区域可用的服务器为基础进行服务器的选择。使用Zone对服务器进行分类,这个Zone可以理解为一个机房、一个机架等。而后再对Zone内的多个服务做轮询。
BestAvailableRule忽略那些短路的服务器,并选择并发数较低的服务器。
RandomRule随机选择一个可用的服务器。
RetryRule重试机制的选择逻辑。

默认为ZoneAvoidanceRule,以区域可用的服务器为基础进行轮询。

如何修改负载均衡策略?

有两种方式:

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

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

在启动类中使用@Bean注解注入一个IRule实例,比如简单地返回一个RandomRule,这样就会改编为随机策略。这是全局配置,即调用所有其他的服务都会应用随机策略。

2.配置文件方式:在order-service的application.yml文件中,添加新的配置:

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

这样配置就会指定某个微服务应用随机策略,这里指定的是userservice。

Ribbon的懒加载和饥饿加载

Ribbon默认的是懒加载,即第一次访问时才会创建LeadBalanceClient,请求时间会很长。而饥饿加载则是在项目启动的时候就进行创建,降低第一次访问的耗时(在加载之后会默认放入缓存,只有第一次会很慢)。

开启饥饿加载的方法——配置:

ribbon:eager-load:enabled: true #开启饥饿加载clients: userservice #指定对userservice这个服务饥饿加载

如果要对多个服务配置则:

ribbon:eager-load:enabled: true #开启饥饿加载clients: - userservice- xxxservice

Nacos注册中心

安装

Nacos是阿里巴巴的产品,由于其更加完善和丰富的功能,现已成为SpringCloud的一个组件。

安装步骤:

1.下载安装包(推荐1.x版本)

2.解压

3.配置:配置conf文件夹里的application.conf,默认端口是8848。

4.启动:Windows命令:startup.cmd -m standalone

访问显示的地址,默认账号和密码都是nacos。

服务注册到Nacos

1.在cloud-demo父工程中添加spring-cloud-alibaba的管理依赖:

<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>

2.注释掉order-service和user-service中原有的eureka依赖。

3.添加nacos的客户端依赖:

<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

4.修改user-service&order-service中的application.yml文件,注释eureka地址,添加nacos地址。

spring:cloud:nacos:server-addr: localhost8848

5.启动并测试。

Nacos服务分级存储模型

服务-集群-实例

服务跨集群调用问题:服务调用尽可能选择本地集群的服务。

服务集群属性配置

1.修改application.yml,添加如下内容:

spring:cloud:nacos:server-addr: localhost:8848discovery:cluster-name: SC #配置集群名称,即机房位置,如SC(四川)

2.在Nacos控制台可以看到集群变化。

优先选择本地集群

在消费者服务中也进行配置,将二者放入同一个集群:

cloud:nacos:server-addr: localhost:8848discovery:cluster-name: SC

要实现优先选择本地集群,需要修改IRule负载均衡策略为NacosRule:

userservice:ribbon:NFLoadBalancerRuleClassName: com.alibaba.cloud.nacos.ribbon.NacosRule

这种策略下会优先选择本地集群基础上采用随机策略。

Nacos权重负载均衡

根据服务器的性能差异进行权重分配

1.在Nacos控制台可以设置实例的权重值,首先选中实例后面的编辑按钮。

2.将权重设置为0.1,测试可以发现被访问到的频率会大大降低。

注:一般设置为0-1之间,权重越高访问频率越高,为0则不会被访问。

Nacos环境隔离——namespace

基于不同的环境(如开发环境、测试环境等)进行隔离。

Nacos会有一个默认的命名空间为public。

在Nacos可以手动创建命名空间,修改命名空间需要再代码中进行。

spring:datasource:url: jdbc:mysql://localhost:3306/test?useSSL=falseusername: rootpassword: 123456driver-class-name: com.mysql.jsbc.Drivercloud:nacos:server-addr: localhost:8848discovery:cluster-name: SCnamespace: 792a7d5d-237b-46a0-a99a-fa8e98e4b0f9 #此处为nacos页面中的命名空间id而不是名称。

注:不同namespace下的服务是不可见的。

Eureka和Nacos的区别

服务消费者拉取信息后会将信息存储到服务列表缓存中,每隔30s重新拉取进行更新。

但是在Nacos中,消费者和提供者的信息拉取和健康监测有所不同。在Nacos中的实例分为临时实例和非临时实例,对于临时实例的提供者来说,和Eureka一样会有一个心跳检测机制,即每隔30s由提供者向Nacos发送信息,如果逾期未发信息就会被Nacos剔除,而非临时实例则是由Nacos主动向提供者发送信息,如果没有得到回复,不会剔除信息,而是会等待实例恢复健康。

对于消费者的信息拉取除了和Eureka一样的由消费者每隔30s主动拉取信息外,如果Nacos收到了来自提供者的不健康的信息,也会主动推送信息给消费者,消费者就能及时更新自己的服务列表缓存。

Nacos设置临时实例和非临时实例
spring:cloud:nacos:discovery:ephemeral: false #设置为非临时实例
Nacos配置管理

解决问题:实现若干微服务的统一配置管理,并且不用重启就能生效,实现热更新。

在Nacos页面选择配置管理,点击“+”手动新建配置,其中DataID一般为服务名称+运行环境+后缀名,如userservice-dev.yaml,配置内容是需要进行热更新的配置,而不是直接把application.yml中的内容直接拷贝。比如pattern: dateformat: yyyy-MM-dd HH:mm:ss。

在项目启动后需要先读取nacos中的配置文件,再读取本地配置文件application.yml,但是nacos配置文件地址又在application.yml文件中,因此需要一个优先级比二者都高的文件来装载nacos地址等相关信息,这个文件就是bootstrap.yml。

统一配置管理的相关设置:
1.引入Nacos的配置管理客户端依赖:

<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>

2.在userservice中的resource目录添加一个bootstrap.yml文件,这个文件是引导文件,优先级高于application.yml:

spring:application:name: userservice #微服务名称profiles:active: dev #开发环境,这里是devcloud:nacos:server-addr: localhost:8848config:file-extension: yaml #文件后缀名

bootstrap.yml文件内容实际上就是nacos配置文件地址+配置文件的ID信息(服务名称+开发环境+文件后缀名)

假设配置的是日期格式pattern,那么可以通过以下方式进行测试:

java">@RestController
@RequestMapping("/user")
public class UserController{//注入nacos中的配置属性@Value("${pattern.dateformat}")private String dateformat;//编写controller,通过日期格式化器来格式化现在时间并返回@GetMapping("now")public String now(){return LocalDate.now().format(DateTimeFormatter.ofPattern(dateformat,Locale.CHINA));}// ...
}
Nacos配置热更新

Nacos中的配置文件更新后,微服务无需重启就可以感知,但是要进行配置。有两种配置方法:

方式一:在@Value注入的变量所在的类上添加@RefreshScope注解

java">@SLf4j
@RestController
@RequestMapping("/user")
@RefreshScope
public class UserController{@Value("${pattern.dateformat}")private String dateformat;
}

方式二:使用@ConfigurationProperties注解(推荐)

java">@Component
@Data
@ConfigurationProperties(prefix="pattern")
public class PatternProperties{private String dateformat;
}

然后自动注入配置类,并且使用get方法获取对象作为参数填入。

java">@RequestMapping("/user")
public class UserController{@Autowiredprivate UserService userService;@Autowiredprivate PatternProperties properties;@GetMapping("now")public String now(){return LocalDateTime.now().format(DateTimeFormatter.ofPattern(properties.getDateFormat))}
}
Nacos集群搭建

在这里插入图片描述

搭建集群的基本步骤:

  • 搭建数据库,初始化数据库表结构
  • 下载nacos安装包
  • 配置nacos
  • 启动nacos集群
  • nginx反向代理
集群Nacos配置

进入nacos的conf目录,找到cluster.conf.example文件,添加ip地址和端口号

如:

127.0.0.1:8845
127.0.0.1:8846
127.0.0.1:8847

配置mysql信息,修改application.properties文件

spring.datasource.platform=mysqldb.mum=1db.url.0=jdbc:mysql://127.0.0.1:3306/nacos?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC
db.user.0=root
db.password.0=123456

复制三份文件(这里是伪集群,因为在同一台服务器上配置),然后修改三个文件夹中的application.properties文件中的端口号

nacos1:

server.port=8845

nacos2:

server.port=8846

nacos3:

server.port=8847

然后分别启动三个nacos节点(不用加-m,默认是集群启动):startup.cmd

nginx反向代理,修改conf/nginx.conf文件
upstream nacos-cluster {server 127.0.0.1:8845;server 127.0.0.1:8846;server 127.0.0.1:8847;
}server {listen	80;server_name localhost;location /nacos {proxy_pass http://nacos-cluster;}
}

然后Java代码中的application.yml文件中nacos端口把8848改为80。

http客户端Feign

RestTemplate方式调用会存在问题,代码可读性差,且如果URL很复杂,使用RestTemplate就会显得不够优雅。

因此可以使用Feign,Feign是一个声明式的http客户端,帮助我们优雅地发送请求。

使用Feign的步骤如下:

1.引入依赖:

<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

2.在order-service的启动类添加注解开启Feign的功能:

java">@EnableFeignClients
@SpringBootApplication
public class OrderApplication{public static void main(String[] args){SpringApplication.run(OrderApplication.class, args);
}

3.编写Feign客户端:

java">@FeignClient("userservice")
public interface UserClient {@GetMapping("/user/{id}")User findById(@PathVariable("id") Long id);
}

使用注解将发送请求所需要的信息进行声明,之后调用这个方法就可以实现发送请求了。

java">public class userService{@Autowiredprivate OrderMapper orderMapper;@Autowiredprivate UserClient userClient;public Order queryOrderById(Long orderId){//1.查询订单Order order = orderMapper.findById(orderId);//2.用Feign远程调用User user = userClient.findById(order.getUserId());//3.封装user到Orderorder.setUser(user);//4.返回return order;}
}

注:feign内部集成了Ribbon,实现了负载均衡。

总结Feign的使用步骤:1.引入依赖;2.添加@EnableFeignClients注解;3.编写FeignClient接口;4.使用FeignClient中定义的方法代替RestTemplate。

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

自定义配置会覆盖默认配置

配置有两种方式,第一种是基于配置文件,第二种是基于Java代码

方式一:配置文件方式

1.全局生效

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

2.局部生效:

feign:client:config:userservice:loggerLevel: FULL

方式二:Java代码方式,需要先声明一个Bean:

java">public class FeignClientConfiguration {@Beanpublic Logger.Level feignLogLevel(){return Logger.Level.BASIC;}
}

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

java">@EnableFeignClients(defaultConfiguration = FeignClientConfiguration.class)

2.如果是局部配置,则放到@FeignClient注解中:

java">@FeignClient(value = "userservice", configuration = FeignClientConfiguration.class)
Feign性能优化

Feign底层的客户端实现由URLConnection(默认实现,不支持连接池)、ApacheHttpClient、OKHttp。

Feign性能优化:
1.使用连接池代替默认的URLConnection。

2.日志级别,最好用basic或者none。

Feign添加HttpClient的支持:

引入依赖:

<dependency><groupId>io.github.openfeign</groupId><artifactId>feign-httpclient</artifactId>
</dependency>

配置连接池:

feign:client:config:default:loogerLevel: BASIC #日志级别,BASIC就是基本的请求和响应信息httpclient:enabled: true #开启feign对HttpClient的支持max-connections: 200 #最大的连接数max-connections-per-route: 50 #每个路径的最大连接数
Feign的最佳实践

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

java">public interface UserAPI{@GetMapping("/user/{id}")User findById(@PathVariable("id") Long id);
}
java">@FeignClient(value = "userservice")
public interface UserClient extends UserAPI{}
java">@RestController
public class UserController implements UserAPI{}

问题:会造成紧耦合,而且父接口参数列表中的映射不会被继承。

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

步骤如下:
1.创建一个module,命名为feign-api,然后引入feign的starter依赖。

<dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId></dependency>
</dependencies>

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

3.在order-service中引入feign-api的依赖,将原有的复制过去的部分删除。

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

<dependency><groupId>cn.itcast.demo</groupId><artifactId>feign-api</artifactId><version>1.0</version>
</dependency>

5.重启测试。

当定义的FeignClient不在SpringBootApplication的扫描包范围时,这些FeignClient无法使用。

有两种方式解决:

方式一:制定FeignClient所在的包:

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

方式二:制定FeignClient字节码(更精准):

java">@EnableFeignCliengts(clients = {UserClient.class})

Gateway统一网关

网关解决的问题:

  • 身份认证和权限校验,避免敏感服务被任意读取。
  • 服务路由,负载均衡。
  • 请求限流。

在SpringCloud中网关的实现包括两种:gateway和zuul。其中zuul是基于Servlet的实现,属于阻塞式编程,而gateway是基于Spring5中提供的WebFlux,属于响应式编程实现,具备更好的性能。

搭建网关服务

1.创建新的module,引入SpringCloudGateway的依赖和nacos的服务发现依赖:

<!--网关依赖-->
<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>

创建启动类

java">@SpringBootApplication
public class GatewayApplication{public static void main(Stringp[] args){SpringApplication.run(GatewayApplication.class, args);}
}

2.编写路由配置及nacos地址:

server:port: 10010 #网关端口
spring:application:name: gateway #服务名称cloud:nacos:server-addr: localhost:8848gateway:routes: #网关路由配置- id: user-service #路由id,自定义,唯一即可# uri: http://127.0.0.1:8081 #路由目标地址,http就是固定地址uri: lb://userservice #路由的目标地址,lb就是负载均衡,后面跟服务名称predicates: #路由断言,也就是判断请求是否符合路由规则的条件- Path=/user/** #这个是按照路径匹配,只要一/user/开头就符合要求

网关路由可以配置的内容包括:

  • 路由id:路由唯一标识
  • uri: 路由目的地,支持lb和http两种
  • predicates:路由断言,判断请求是否符合要求,符合则转发到路由目的地
  • filters:路由过滤器,处理请求或响应

在这里插入图片描述

路由断言工厂

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

Spring提供了11种基本的断言工厂:

名称说明示例
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权重处理

例如使用After:

predicates:- Oath=/order/**- After=2031-04-13T15:14:47.433+08:00[Asia/Shanghai]

时间不在规定范围之后就会404。

路由过滤器GatewayFilter

可以对进入网关的请求和微服务返回的响应做处理。

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

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

例如:给userservice的路由添加过滤器,所有进入userservice的请求添加一个请求头。

spring:cloud:gateway:route: #网关路由配置- id: user-serviceuri: lb://userservicepredicates:- Path=/user/**filters: #过滤器- AddRequestHeader=Truth, Itcast is freaking awosome! #添加请求头
java">@GetMapping("/{id}")
public User quertById(@PathVariable("id") Long id,@RequestHeader(value = "Truth", required = false) String truth){System.out.println("truth:" + truth);return userService.queryById(id);
}

如果要对所有的路由都生效,需要将路由过滤器配置到default-filters下,在任意一个服务中配置都可以:

spring:application:name: gatewaycloud:nacos:server-addr: localhost:8848gateway:routes:- id: user-serviceuri: lb://userservicepredicates:- Path=/user/**- id: order-serviceuri: ln://orderservicepredicates:- Path=/order/**default-filters:- AddRequestHeader=Truth, Itcast is freaming awesome!
全局过滤器GlobalFilter

前面的过滤器是通过配置定义的,是spring写死的,而要实现自定义配置,就可以通过GlobalFilter。定义方式就是实现GlobalFIlter接口。

java">public ingterface GlobalFilter{/***	处理当前请求,有必要的话通过{@Link GatewayFilterChain}将请求交给下一个过滤器处理*   @Param exchange 请求上下文,里面可以获取Request、Response等信息*	@Param chain 用来把请求委托给下一个过滤器*	@return {@code Mono<Void>} 返回标识当前过滤器业务结束*/Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain);
}

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

需求:定义全局过滤器,拦截请求,判断请求的参数是否满足下面条件:

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

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

实现步骤:1.获取请求参数 2.获取参数中的authorization参数 3.判断参数值是否等于admin 4.如果是则放行,否则拦截。

java">@Order(-1)
@Component
public class AuthorizeFilter implements GlobalFilter{@Overridepublic 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.判断参数值是否等于adminif ("admin".equals(auth)){//4.是,放行return chain.filter(exchange);}//5.否,拦截//5.1.设置状态码exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);//5.2.拦截请求return exchange.getResponse()/setComplete();}
}

注:@Order()里面的值是int值的取值范围,可以为负数,越小优先级越高。

过滤器执行顺序

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

请求路由后,会将这三种过滤器合并到一个过滤器链(集合)中,排序后依次执行每个过滤器。

  • 每个过滤器都必须指定一个int类型的order值,值越小优先级越高,执行顺序越靠前。
  • GlobalFilter通过实现Ordered接口或者添加@Order注解来指定order值,由程序员指定。
  • 路由过滤器和defaultFilter的order由spring指定,默认是按照声明顺序从1递增。
  • 当过滤器的order值一样时,会按照defaultFilter > 路由过滤器 > GlobalFilter的顺序执行。
跨域问题处理

跨域:域名不一致就是跨域,包括:域名不同,域名相同但端口不同。

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

解决方案: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 #是否允许携带cookiemaxAge: 360000 #这次跨域检测的有效期

}
}

注:@Order()里面的值是int值的取值范围,可以为负数,越小优先级越高。

过滤器执行顺序

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

请求路由后,会将这三种过滤器合并到一个过滤器链(集合)中,排序后依次执行每个过滤器。

  • 每个过滤器都必须指定一个int类型的order值,值越小优先级越高,执行顺序越靠前。
  • GlobalFilter通过实现Ordered接口或者添加@Order注解来指定order值,由程序员指定。
  • 路由过滤器和defaultFilter的order由spring指定,默认是按照声明顺序从1递增。
  • 当过滤器的order值一样时,会按照defaultFilter > 路由过滤器 > GlobalFilter的顺序执行。
跨域问题处理

跨域:域名不一致就是跨域,包括:域名不同,域名相同但端口不同。

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

解决方案: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 #是否允许携带cookiemaxAge: 360000 #这次跨域检测的有效期

http://www.ppmy.cn/embedded/137590.html

相关文章

深入探讨 .NET Core 3.0 浮点计算差异与解决方案

在 .NET Core 3.0 中&#xff0c;对浮点解析和格式进行了更改&#xff0c;以符合 IEEE 754-2008 标准。您可以在这篇文章中阅读有关这些更改的更多信息。在使用 Stimulsoft 产品时&#xff0c;这些更改最常表现为舍入数字和出现“负号”零。 Stimulsoft Ultimate &#xff08;…

微服务相关问题

什么是雪崩 1、微服务相互调用&#xff0c;服务提供者出现故障或阻塞&#xff1b; 2、服务调用者没有做好异常处理&#xff0c;导致自身故障&#xff1b; 3、调用链中的所有服务级联失败&#xff0c;导致整个集群故障&#xff1b; 解决思路 1、尽量避免服务出现故障或阻塞&…

matlab生成m序列(数字图像水印相关)

m序列 定义 m序列是一种重要的伪随机序列&#xff08;PN序列&#xff09;&#xff0c;它是由线性反馈移位寄存器产生的周期最长的序列&#xff0c;其规律性强&#xff0c;有很好的自相关性和较好的互相关特性。 周期由什么决定&#xff1f; 既然m序列是周期最长的序列&…

C#封装EPPlus库为Excel导出工具

1&#xff0c;添加NUGet包 2&#xff0c;封装工具类 using OfficeOpenXml; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection;namespace GMWPF.utils {public class ExcelUtil<T>{/// <summary>///…

什么是 ISP:了解互联网服务提供商的作用

一、ISP 基础知识 从本质上讲&#xff0c;ISP 提供两项主要服务&#xff1a;互联网接入和互联网传输。互联网接入是指使用户能够连接到互联网的物理和逻辑连接&#xff0c;通常通过调制解调器、路由器或其他网络设备。此连接可以是有线的&#xff08;例如通过 DSL、光纤或电缆…

使用element UI实现表格行/列合并

前言 本文代码使用vue2element UI&#xff0c;通过给table传入span-method方法实现合并行或列 效果图 示例代码 后端返回数据格式如下 {"total": 12,"records": [[{"id": 1,"project": "田径","subitem": &qu…

探索Scala编程:图书管理系统实战

在这篇文章中&#xff0c;我们将通过一个简单的图书管理系统项目来深入理解Scala编程。这个项目不仅会帮助你掌握Scala的基本操作&#xff0c;还会让你了解如何使用Scala来处理实际问题。准备好了吗&#xff1f;让我们开始吧&#xff01; 项目目标 我们的目标是创建一个图书管…

1.2 数据结构的分类与应用

1.2 数据结构的分类与应用 数据结构&#xff0c;就是字面意思&#xff0c;一门用来研究数据如何高效的在计算机中进行存储和查询的学科。几乎所有的数据结构&#xff0c;也都是从生活中和数学理论中&#xff0c;衍生而来。 下表列出了常见的数据结构&#xff0c;我们先来熟悉一…