SpringCloud学习笔记

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、端口:

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

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

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

@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,那么可以通过以下方式进行测试:

@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注解

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

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

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

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

@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的功能:

@EnableFeignClients
@SpringBootApplication
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);
}

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

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:

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

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

@EnableFeignClients(defaultConfiguration = FeignClientConfiguration.class)

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

@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定义统一的父接口作为标准。

public interface UserAPI{@GetMapping("/user/{id}")User findById(@PathVariable("id") Long id);
}
@FeignClient(value = "userservice")
public interface UserClient extends UserAPI{}
@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所在的包:

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

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

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

创建启动类

@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! #添加请求头
@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接口。

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.如果是则放行,否则拦截。

@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.rhkb.cn/news/470901.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

HBase理论_背景特点及数据单元及与Hive对比

本文结合了个人的笔记以及工作中实践经验以及参考HBase官网&#xff0c;我尽可能把自己的知识点呈现出来&#xff0c;如果有误&#xff0c;还请指正。 1. HBase背景 HBase作为面向列的数据库运行在HDFS之上&#xff0c;HDFS缺乏随机读写操作&#xff0c;HBase正是为此而出现。…

MoneyPrinterTurbo – 开源的AI短视频生成工具

MoneyPrinterTurbo是什么 MoneyPrinterTurbo是开源的AI短视频生成工具&#xff0c;能自动化地根据用户提供的视频主题或关键词生成视频文案、素材、字幕和背景音乐&#xff0c;合成高清短视频。工具支持API和Web界面操作&#xff0c;具备自定义文案、多种视频尺寸、批量视频生…

[CKS] K8S NetworkPolicy Set Up

最近准备花一周的时间准备CKS考试&#xff0c;在准备考试中发现有一个题目关于不安全项目修复的题目。 ​ 专栏其他文章: [CKS] Create/Read/Mount a Secret in K8S-CSDN博客[CKS] Audit Log Policy-CSDN博客 -[CKS] 利用falco进行容器日志捕捉和安全监控-CSDN博客[CKS] K8S Ne…

DataWorks on EMR StarRocks,打造标准湖仓新范式

在大数据领域&#xff0c;数据仓库和实时分析系统扮演着至关重要的角色。DataWorks 基于大数据引擎&#xff0c;为数据仓库/数据湖/湖仓一体等解决方案提供统一的全链路大数据开发治理平台&#xff0c;为用户带来智能化的数据开发和分析体验。而阿里云提供的 EMR Serverless St…

设计模式之责任链模式(Chain Of Responsibility)

一、责任链模式介绍 1、责任链模式介绍 职责链模式(chain of responsibility pattern) 定义: 避免将一个请求的发送者与接收者耦合在 一起&#xff0c;让多个对象都有机会处理请求。将接收请求的对象连接成一条链&#xff0c;并且沿着这条链 传递请求&#xff0c;直到有一个对…

Qt_day4_Qt_UI设计

目录 Qt_UI设计 1. Designer 设计师&#xff08;掌握&#xff09; 2. Layout 布局&#xff08;重点&#xff09; 2.1 基本使用 2.2 高级用法 2.3 代码布局&#xff08;了解&#xff09; 3. Designer与C的关系&#xff08;熟悉&#xff09; 4. 基本组件&#xff08;掌握…

Unity学习笔记(4):人物和基本组件

文章目录 前言开发环境新增角色添加组件RigidBody 2D全局项目设置Edit 给地图添加碰撞体 总结 前言 今天不加班&#xff0c;有空闲时间。争取一天学一课&#xff0c;养成习惯 开发环境 Unity 6windows 11vs studio 2022Unity2022.2 最新教程《勇士传说》入门到进阶&#xff…

Elastic Observability 8.16:增强的 OpenTelemetry 支持、高级日志分析和简化的入门流程

作者&#xff1a;来自 Elastic Luca Wintergerst, Alex Fedotyev, Vinay Chandrasekhar, Miguel Luna Elastic Observability 8.16 宣布了几个关键功能&#xff1a; Amazon Bedrock 集成 LLM 可观察性为基于 Amazon Bedrock 构建的 LLM 应用程序添加了全面的监控功能。这种新的…

Bugku CTF_Web——文件上传

Bugku CTF_Web——文件上传 进入靶场 My name is margin,give me a image file not a php抓个包上传试试 改成png也上传失败 应该校验了文件头 增加了文件头也不行 试了一下 把文件类型改成gif可以上传 但是还是不能连接 将Content-Type改大小写 再把文件后缀名改成php4 成…

车-路-站-网”信息耦合的汽车有序充电

电动汽车作为一种环保、的交通工具&#xff0c;正逐渐成为未来交通的发展趋势。然而&#xff0c;大规模电动汽车的无序充电可能导致电网负荷波动、电压下降等问题&#xff0c;影响电网的安全稳定运行。为了解决这些问题&#xff0c;需要制定有效的电动汽车有序充电策略&#xf…

Microsoft 365 Exchange如何设置可信发件IP白名单

1、 进入到 Microsoft 365 admin center 管理中心 &#xff0c;点击 管理中心 下的 安全 在弹出的新页面中&#xff0c;依次点击 策略和规则 – 威胁策略 – 反垃圾邮件 再单击 连接筛选器策略(默认) – 编辑连接筛选器策略 2、在 IP 允许列表 中添加可信邮件 IP 段&#xff0…

什么岗位需要学习 OpenGL ES ?说说 3.X 的新特性

什么是 OpenGL ES OpenGL ES 是一种为嵌入式系统和移动设备设计的3D图形API(应用程序编程接口)。它是标准 OpenGL 3D 图形库的一个子集,专门为资源受限的环境(如手机、平板电脑、游戏机和其他便携式设备)进行了优化。 由于其在移动设备上的广泛适用性,OpenGL ES是学习移…

力扣104 : 二叉树最大深度

补&#xff1a;二叉树的最大深度 描述&#xff1a; 给定一个二叉树 root &#xff0c;返回其最大深度。二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。 何解&#xff1f; 树一般常用递归&#xff1a;递到叶子节点开始倒着处理

免费,WPS Office教育考试专用版

WPS Office教育考试专用版&#xff0c;不仅满足了考试需求&#xff0c;更为教育信息化注入新动力。 https://pan.quark.cn/s/609ef85ae6d4

[运维][Nginx]Nginx学习(1/5)--Nginx基础

Nginx简介 背景介绍 Nginx一个具有高性能的【HTTP】和【反向代理】的【WEB服务器】&#xff0c;同时也是一个【POP3/SMTP/IMAP代理服务器】&#xff0c;是由伊戈尔赛索耶夫(俄罗斯人)使用C语言编写的&#xff0c;Nginx的第一个版本是2004年10月4号发布的0.1.0版本。另外值得一…

《新智慧》期刊的征稿范围主要包括哪些方面?

一、教育教学理论与实践&#xff1a; 教学方法创新&#xff1a;例如新颖的课堂教学模式、教学策略的探索与实践&#xff0c;如小组合作学习、项目式学习、探究式学习等教学方法在不同学科教学中的应用及效果研究。 课程改革研究&#xff1a;对基础教育、中等教育阶段的课程改革…

Golang | Leetcode Golang题解之第559题N叉树的最大深度

题目&#xff1a; 题解&#xff1a; func maxDepth(root *Node) (ans int) {if root nil {return}queue : []*Node{root}for len(queue) > 0 {q : queuequeue nilfor _, node : range q {queue append(queue, node.Children...)}ans}return }

C++初阶:类和对象(上)

1. 类的定义 1.1 类的定义格式 class为定义类的关键字&#xff0c;Stack为类的名字&#xff0c;{ } 中为类的主体&#xff0c;注意类定义结束后的分号不能省略。类体中的内容为类的成员&#xff1a;类中的变量称为类的属性或成员变量&#xff1b;类中的函数称为类的方法或成员…

linux设置主机名

1、查看主机名 hostname默认&#xff1a; localhost.localdomain 2、更改主机名 编辑/etc/hostname&#xff0c;修改成自己需要的主机名&#xff0c;如self-name 3、设置hosts 编辑/etc/hosts&#xff0c;将修改的主机名增加一个映射 127.0.0.1 localhost localhost.lo…

MybatisPlus入门(十)MybatisPlus-逻辑删除和多记录操作

一、Mybatis-Plus 多记录操作 按照主键删除多条记录 List<Long> ids Arrays.asList(new Long[]{2,3}) userDao.deleteBatchIds(ids); 示例代码如下: Testvoid testDelete(){//删除指定多条数据List<Long> list new ArrayList<>();list.add(14025513424818…