续(一)
负载均衡的第二种实现方式Feign
前面在使用Ribbon + RestTemplate时,利用RestTemplate对Http请求的封装处理,形成了一套模板化的调用方法。,但是使用 RestTemplate 还是不方便,这样每次都调用 RestRemplate 的 API 太麻烦,我能不能像调用原来代码一样进行各个服务间的调用呢?那就用映射,就像域名和IP地址的映射。我们可以将被调用的服务代码映射到消费者端。所以,Feign在此基础上做了进一步的封装,由他来帮助我们定义和实现依赖服务接口的定义,在Feign的实现下,我们只需要创建一个接口并使用注解的方式来配置它 (类似以前Dao接口上标注Mapper注解,现在是一个微服务接口上面标注一个Feign注解),即可完成对服务提供方的接口绑定,简化了使用Spring Cloud Ribbon 时,自动封装服务调用客户端的开发量。
Feign,主要是社区版,大家都习惯面向接口编程。这个是很多开发人员的规范。调用微服务访问两种方法。
微服务名字 【ribbon】
接口和注解 【feign】
但是要注意的是,Feign集成了Ribbon,它下面用的还是Ribbon,只是进行了封装而已。
实现步骤
1:在基础的模块中导入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
2:创建一个接口,关联到我们的服务
package com.dongmu.service;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
@Component
@FeignClient(value = "SPRINGCLOUD-PROVIDER-DEPT")
public interface DeptService {
@GetMapping("/api/dept")
String getDept(Long id);
}
![在这里插入图片描述](https://img-blog.csdnimg.cn/a145314884ba45749638778323196b73.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5YyX5rW35Yal6bG85pyq55yg,size_20,color_FFFFFF,t_70,g_se,x_16)
3:通过接口来调用我们的服务。
创建一个消费者,加入下面的依赖
<dependency>
<groupId>org.example</groupId>
<artifactId>springCloud-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
在消费者这种调用刚才接口里面的方法
package com.dongmu.controller;
import com.dongmu.service.DeptService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class DeptController {
@Autowired
DeptService deptService;
@RequestMapping("rpc/getDept")
public String rpcGetDept(Long id){
return deptService.getDept(id);
}
}
创建一个启动类
package com.dongmu;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.ComponentScan;
@SpringBootApplication
@ComponentScan("com.dongmu.*")
@EnableEurekaClient
@EnableFeignClients(basePackages = "com.dongmu.service")
public class ConsumerApplication_8802 {
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication_8802.class,args);
}
}
配置文件
server:
port: 8802
eureka:
client:
register-with-eureka: false #不向eureka中注册自己,消费者只需要拿服务即可。
service-url:
defaultZone: http://localhost:7002/eureka/,http://localhost:7003/eureka/,http://localhost:7001/eureka/
# fetch-registry: true #true表示去注册中心检索服务
启动进行访问(报错500)
记录一下错误地方,排错好久,哎、
![在这里插入图片描述](https://img-blog.csdnimg.cn/c337e303c3814d13b46182efa4f046b3.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5YyX5rW35Yal6bG85pyq55yg,size_20,color_FFFFFF,t_70,g_se,x_16)
通过8002访问成功,默认是轮询。修改负载均衡的方式和Ribbon是一样的,亲测。
![在这里插入图片描述](https://img-blog.csdnimg.cn/0f5c76a1c75844cb9c77b758d18cfe7e.png)
Feign可以支持很多的自定义配置,如下表所示:
![在这里插入图片描述](https://img-blog.csdnimg.cn/24c26f12aa874b30896e5cc98b2088c6.png)
一般情况下,默认值就能满足我们使用,如果要自定义时,只需要创建自定义的@Bean覆盖默认Bean即可。
比如我们想要修改日志的级别,可以在配置文件里面按如下填写,当然,如果我们也可以使用注解的方式。
feign:
client:
config:
userservice: # 针对某个微服务的配置,如果写default就是针对全局
loggerLevel: FULL # 日志级别
基于注解的方式,首先需要声明一个对象
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)
另外,Feign只是一种风格,底层还是调用了http请求,底层使用的是URLConnection,不支持连接池,效率比较低,我们可以使用ApacheHttpClient或者OKHttp,这两种都支持连接池。我们使用的时候替换默认的http请求工具即可。使用方式如下
<!--httpClient的依赖 -->
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-httpclient</artifactId>
</dependency>
feign:
client:
config:
default: # default全局的配置
loggerLevel: BASIC # 日志级别,BASIC就是基本的请求和响应信息
httpclient:
enabled: true # 开启feign对HttpClient的支持
max-connections: 200 # 最大的连接数
max-connections-per-route: 50 # 每个路径的最大连接数
断路器——Netflix Hystrix
在介绍Hystrix之前,我们先了解一些基本的概念
雪崩效应
在微服务架构中,为了保证其高可用,单个服务通常会集群部署。由于网络原因或者自身的原因,服务并不能保证100%可用,如果单个服务出现问题,调用这个服务就会出现线程阻塞,此时若有大量的请求涌入,Servlet容器的线程资源会被消耗完毕,导致服务瘫痪。如客户端访问 A 服务,而 A 服务需要调用 B 服务,B 服务需要调用 C 服务,由于网络原因或者自身的原因,如果 B 服务或者 C 服务不能及时响应,A 服务将处于阻塞状态,直到 B 服务 C 服务响应。此时若有大量的请求涌入,容器的线程资源会被消耗完毕,导致服务瘫痪。服务与服务之间的依赖性,故障会传播,造成连锁反应,会对整个微服务系统造成灾难性的严重后果,这就是服务故障的“雪崩”效应。
造成雪崩的原因可以归结为以下三点:
- 服务提供者不可用(硬件故障,程序 BUG,缓存击穿,用户大量请求等)
- 重试加大流量(用户重试,代码逻辑重试)
- 服务消费者不可用(同步等待造成的资源耗尽)
最终的结果就是:一个服务不可用,导致一系列服务的不可用。
Netflix Hystrix是SOA/微服务架构中提供服务隔离、熔断、降级机制的工具/框架。Netflix Hystrix是断路器的一种实现,用于高微服务架构的可用性,是防止服务出现雪崩的利器。。
雪崩是系统中的蝴蝶效应导致,其发生的原因多种多样,从源头我们无法完全杜绝雪崩的发生,但是雪崩的根本原因来源于服务之间的强依赖,所以我们可以提前评估做好服务容错。解决方案大概可以分为以下几种:
- 请求缓存:支持将一个请求与返回结果做缓存处理;
- 请求合并:将相同的请求进行合并然后调用批处理接口;
- 服务隔离:限制调用分布式服务的资源,某一个调用的服务出现问题不会影响其他服务调用;
- 服务熔断:牺牲局部服务,保全整体系统稳定性的措施;
- 服务降级:服务熔断以后,客户端调用自己本地方法返回缺省值。降级是为了更好的用户体验,当一个方法调用异常时,通过执行另一种代码逻辑来给用户友好的回复。对应着 Hystrix 的后备处理模式
参考文章,叙述非常清楚
服务熔断
1:先创建一个服务提供者,方式和之前普通的方式一样,
然后加入依赖
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-eureka -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
<version>1.4.7.RELEASE</version>
</dependency>
2:编写我们的服务
package com.dongmu.controller;
import com.dongmu.dao.DeptMapper;
import com.dongmu.pojo.Dept;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.ribbon.proxy.annotation.Hystrix;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
package com.dongmu.controller;
import com.dongmu.dao.DeptMapper;
import com.dongmu.pojo.Dept;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.ribbon.proxy.annotation.Hystrix;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class DeptController {
@Autowired
DeptMapper deptMapper;
@ResponseBody
@PostMapping("/deptAdd")
public String addDept(){
Dept dept = new Dept("测试部"+System.currentTimeMillis());
deptMapper.insertSelective(dept);
return dept.toString();
}
@ResponseBody
@GetMapping("/deptGet")
@HystrixCommand(fallbackMethod = "hystrixGet")
public String gerDept(@RequestParam(value = "id") Long id){
// dept.setDeptno(id);
Dept dept = deptMapper.selectByPrimaryKey(id);
if (dept==null){
throw new RuntimeException("不存在这个用户,请重新输入。");
}
return dept.toString();
}
//发送异常的备选方法
public String hystrixGet(@RequestParam(value = "id") Long id){
return "不存在这个用户,请重新输入。_Hystrix";
}
}
- @HystrixCommand(fallbackMethod = “hystrixGet”)就是我们方法返回失败了执行其他的方法。服务熔点。
4:主启动类上添加对熔断的支持
package com.dongmu;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ComponentScan;
@SpringBootApplication
@ComponentScan("com.dongmu.*")
@EnableEurekaClient
@EnableCircuitBreaker//添加对熔断的支持,就是断路器
public class ProviderApplication_8004 {
public static void main(String[] args) {
ConfigurableApplicationContext run = SpringApplication.run(ProviderApplication_8004.class, args);
}
}
启动项目进行测试:
![在这里插入图片描述](https://img-blog.csdnimg.cn/5be532bb01f24efe868eab460b0679d5.png)
采用轮询,可以发现其他的服务会出现异常,但是这个服务对请求进行了熔断。
服务降级
1:在基础模块里面加入下面这个类
package com.dongmu.service;
import feign.hystrix.FallbackFactory;
import org.springframework.stereotype.Component;
@Component
/*
FallbackFactory可以用来处理我们失败的回调
*/
public class DeptServiceFallBackFactory implements FallbackFactory {
@Override
//返回值表示我们要处理的类,直接一下子处理一个类中所有的方法。
public DeptService create(Throwable throwable) {
return new DeptService() {
@Override
public String getDept(Long id) {
return "服务降级执行的服务。";
}
};
}
}
2:在我们刚才的feign里面添加一个注解的属性,指定我们失败回调的类的class
package com.dongmu.service;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
@Component
@FeignClient(value = "SPRINGCLOUD-PROVIDER-DEPT",fallbackFactory = DeptServiceFallBackFactory.class)
public interface DeptService {
@GetMapping("/api/deptGet")
String getDept(@RequestParam( value = "id") Long id);
}
![在这里插入图片描述](https://img-blog.csdnimg.cn/5464cd0ceaf840d4879cab7dda1afc44.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5YyX5rW35Yal6bG85pyq55yg,size_20,color_FFFFFF,t_70,g_se,x_16)
3:在feign的消费者端开启服务降级的支持。
server:
port: 8802
eureka:
client:
register-with-eureka: false #不向eureka中注册自己,消费者只需要拿服务即可。
service-url:
defaultZone: http://localhost:7002/eureka/,http://localhost:7003/eureka/,http://localhost:7001/eureka/
#fetch-registry: true #true表示去注册中心检索服务
feign:
hystrix:
enabled: true
然后启动服务,继续访问
注意:我们刚才的服务熔断是在服务端进行的,写了另一个处理失败调用的方法,但是这里服务降级我们没有在服务端进行任何操作,仅仅是在消费者端进行了一些配置
![在这里插入图片描述](https://img-blog.csdnimg.cn/3b02ae908dc540a3b68911e0976e3d2d.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/066174e3634744118faac2a6b201ea27.png)
可以发现,在访问其他三个服务器的时候执行了服务降级的处理,在执行第四个服务器中进行了服务熔断的处理的地方,返回了服务熔断的处理。
我们查询正常存在的数据
![在这里插入图片描述](https://img-blog.csdnimg.cn/36d43d3e1fbd4a18868c0854540d5de4.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/5026b77257c649c2b8720eb36730a1ec.png)
都可以访问,这时候我们把服务1关掉,它还是会走其他的请求,我们把四个服务全都关闭,再进行访问,出现服务降级。只要还有针对于这个请求可以用的服务就不会出现服务降级,我们要把所有的服务全部关闭就可以看到服务降级。
![在这里插入图片描述](https://img-blog.csdnimg.cn/4cf9617f447649c09cccb1fae90ea5ec.png)
服务熔断和降级的区别联系
- 服务熔断一般是某个服务(下游服务)故障引起,而服务降级一般是从整体负荷考虑;
- 目的很一致,都是从可用性可靠性着想,为防止系统的整体缓慢甚至崩溃,采用的技术手段;
- 服务熔断:一般是某个服务异常引起的,相当于“保险丝”,当某个异常条件被触发,直接熔断整个服务,不是等到此服务超时
- 服务降级:降级一般是从整体负荷考虑,当某个服务熔断之后,服务器将不再被调用,客户端可自己准备一个本地的fallback回调,返回一个缺省值,虽然服务水平下降,但是能用,比直接挂掉要强
Dashboard监控页面
1:创建一个监控模块添加依赖
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-eureka -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
<version>1.4.7.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-eureka -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix-dashboard</artifactId>
<version>1.4.7.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-eureka -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.example</groupId>
<artifactId>springCloud-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
同时注意保证服务端要含有这个依赖
<!--这个包可以帮助我们配置当前这个服务在Eureka中监控页面的信息-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
2:配置一个端口
server:
port: 8803
3:添加启动类,开启监控支持
package com.dongmu;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard;
@SpringBootApplication
@EnableHystrixDashboard//开启监控支持
public class HystrixDashBoardApplication {
public static void main(String[] args) {
SpringApplication.run(HystrixDashBoardApplication.class,args);
}
}
启动进行访问
![在这里插入图片描述](https://img-blog.csdnimg.cn/0b411af3adc443ff960b8fa2d1d0e5cc.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5YyX5rW35Yal6bG85pyq55yg,size_20,color_FFFFFF,t_70,g_se,x_16)
访问成功。
在添加了熔断机制的服务者启动类中进行注册
@Bean
public ServletRegistrationBean registrationBean(){
ServletRegistrationBean registrationBean = new ServletRegistrationBean<>(new HystrixMetricsStreamServlet());
registrationBean.addUrlMappings("/actuator/hystrix.stream");
return registrationBean;
}
![在这里插入图片描述](https://img-blog.csdnimg.cn/f860799e2edb4fd9bfb04bfff185ea4d.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5YyX5rW35Yal6bG85pyq55yg,size_20,color_FFFFFF,t_70,g_se,x_16)
注意这个路径要带上自己的项目名
进入监视页面,第三个空名字只是给这个监控起一个名字
![在这里插入图片描述](https://img-blog.csdnimg.cn/2d08e1fcffe5471fb57be4a5be3a7624.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5YyX5rW35Yal6bG85pyq55yg,size_20,color_FFFFFF,t_70,g_se,x_16)
登录进入之后我们一边刷新访问一遍观察监控页面
![在这里插入图片描述](https://img-blog.csdnimg.cn/d74a4b7bde714abdb6075f1cbdd1c524.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5YyX5rW35Yal6bG85pyq55yg,size_20,color_FFFFFF,t_70,g_se,x_16)
![在这里插入图片描述](https://img-blog.csdnimg.cn/bc60bf2a6ba242b58888f357e0b533b7.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5YyX5rW35Yal6bG85pyq55yg,size_20,color_FFFFFF,t_70,g_se,x_16)
服务网关——Netflix Zuul
什么是Zuul?
API网关为微服务架构中的服务提供了统一的访问入口,客户端通过API网关访问相关服务。API网关的定义类似于设计模式中的门面模式,它相当于整个微服务架构中的门面,所有客户端的访问都通过它来进行路由及过滤。
zuul 是netflix开源的一个API Gateway 服务器, 本质上是一个web servlet应用。Zuul 在云平台上提供动态路由,监控,弹性,安全过滤等边缘服务的框架。主要功能如下:
使用步骤
1:创建一个路由模块添加依赖
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-eureka -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zuul</artifactId>
<version>1.4.7.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-eureka -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
<version>1.4.7.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-eureka -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix-dashboard</artifactId>
<version>1.4.7.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-eureka -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.example</groupId>
<artifactId>springCloud-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
2:配置文件
server:
port: 9527
spring:
application:
name: springcloud-zuul
eureka:
client:
service-url:
#这里写远程注册中心的地址,由于测试的时候注册中心就在本机所以写的是localhost
defaultZone: http://localhost:7001/eureka/,http://localhost:7002/eureka/,http://localhost:7003/eureka/
instance:
#这个会显示再远程eureka的面板上
instance-id: Zuul_9527.com
prefer-ip-address: true
info:
app.name: DONGMU_SpringCloud
company.name: BEIHAI
3:启动类
package com.dongmu;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
@SpringBootApplication
@EnableZuulProxy
public class ZuulApplication {
public static void main(String[] args) {
SpringApplication.run(ZuulApplication.class,args);
}
}
启动查看eureka注册中心
![在这里插入图片描述](https://img-blog.csdnimg.cn/460f87eca8e1439fb5f186e3a324149b.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5YyX5rW35Yal6bG85pyq55yg,size_20,color_FFFFFF,t_70,g_se,x_16)
可以看到服务已经成功了。然后我们直接通过路由访问注册中心的服务。
![在这里插入图片描述](https://img-blog.csdnimg.cn/2928e4cd6e01464e8f30ace666890b99.png)
但是这个里面会暴露我们服务的名字,我们在zuul的配置文件中添加
zuul:
routes:
mydept.serviceId: springcloud-provider-dept
mydept.path: /dept/**
然后把服务名字换成dept来访问
![在这里插入图片描述](https://img-blog.csdnimg.cn/74f3b9ae486143188c13c3d1857f9e1e.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5YyX5rW35Yal6bG85pyq55yg,size_20,color_FFFFFF,t_70,g_se,x_16)
但是存在一个问题,就是原来的路径还是能够访问。
![在这里插入图片描述](https://img-blog.csdnimg.cn/5ed0fe4a5edf48d08fade06357bfc83d.png)
我们继续添加配置
zuul:
routes:
mydept.serviceId: springcloud-provider-dept
mydept.path: /dept/**
ignored-services:
- springcloud-provider-dept
之后就无法访问了。
![在这里插入图片描述](https://img-blog.csdnimg.cn/43fa7292ca7e491495d411dae6a5f846.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5YyX5rW35Yal6bG85pyq55yg,size_20,color_FFFFFF,t_70,g_se,x_16)
修改的路径依然能够访问
![在这里插入图片描述](https://img-blog.csdnimg.cn/8b2bb9fca791474da676ec96b01f3636.png)
网关配置断言
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/开头就符合要求
我们在配置文件中写的断言规则只是字符串,这些字符串会被Predicate Factory读取并处理,转变为路由判断的条件。
例如Path=/user/**是按照路径匹配,这个规则是由org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory
类来处理的,像这样的断言工厂在SpringCloudGateway还有十几个,大家可以自行百度。
过滤器工厂
GatewayFilter是网关中提供的一种过滤器,可以对进入网关的请求和微服务返回的响应做处理。Spring提供了31种不同的路由过滤器工厂,例如
名称 |
说明 |
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! # 添加请求头
如果要对所有的路由都生效,则可以将过滤器工厂写到default下。格式如下:
spring:
cloud:
gateway:
routes:
- id: user-service
uri: lb://userservice
predicates:
- Path=/user/**
default-filters: # 默认过滤项
- AddRequestHeader=Truth, Itcast is freaking awesome!
全局过滤器
全局过滤器的作用也是处理一切进入网关的请求和微服务响应,与GatewayFilter的作用一样。区别在于GatewayFilter通过配置定义,处理逻辑是固定的;而GlobalFilter的逻辑需要自己写代码实现。
定义方式是实现GlobalFilter接口。
public interface GlobalFilter {
/**
* 处理当前请求,有必要的话通过{@link GatewayFilterChain}将请求交给下一个过滤器处理
*
* @param exchange 请求上下文,里面可以获取Request、Response等信息
* @param chain 用来把请求委托给下一个过滤器
* @return {@code Mono<Void>} 返回标示当前过滤器业务结束
*/
Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain);
}
网关解决跨域问题
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 # 这次跨域检测的有效期
参考视频1
参考视频2