前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >springClound --- 中级篇(1)

springClound --- 中级篇(1)

作者头像
贪挽懒月
发布2020-06-08 12:04:21
1.1K0
发布2020-06-08 12:04:21
举报
文章被收录于专栏:JavaEEJavaEE

本系列笔记涉及到的代码在GitHub上,地址:https://github.com/zsllsz/cloud

本文涉及知识点:

  • 服务降级熔断之hystrix;
  • 服务网关之gateway;

一、服务降级&熔断&限流之Hystrix(豪猪)

1、微服务面临的问题: 将一个个的业务拆分出来,独立成一个个服务,降低了系统的耦合度,但是也面临了一些问题。比如实现业务场景一需要调用服务A,A又要调用B,B还要调用C……,这叫做“扇出”,就是各个微服务相互调用,像一把折扇一样。如果B挂了,那就导致整条链路不能用了,就出现了服务雪崩的情况。为了解决这种问题,就需要一种名为“服务降级和熔断”的办法。

2、Hystrix是什么? Hystrix就是服务降级和熔断的一种落地实现。可以保证当某个服务超时、异常的情况下,不会导致整体服务雪崩,避免级联故障,提高分布式系统的弹性。它会在当某个服务超时、异常的时候,返回一个符合预期格式、可处理的备选响应给调用者,从而保证了服务的可用。

3、Hystrix能干嘛:

  • 服务降级:fallback,比如我们写代码的时候,有下面这种情况:
代码语言:javascript
复制
if () {

} else if () {

} else {

}

这里最后的else就是服务降级,就是给一个兜底的解决方案。 会发生服务降级的情况:程序异常、响应超时、服务熔断触发降级、线程池/信号量打满也会导致服务降级。

  • 服务熔断:break,就像保险丝熔断一样,当服务达到了所能承受的最大访问量后,就拉闸断电,调用服务降级给用户返回友好的提示。
  • 服务限流:flowlimit,在秒杀等高并发的场景下,严禁一窝蜂地访问系统,而是排队访问,一秒钟N个,有序进行。

4、cloud-provider-hystrix-payment8001项目搭建: 新建一个名为cloud-provider-hystrix-payment8001的module。

  • pom.xml:
代码语言:javascript
复制
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-devtools</artifactId>
    <scope>runtime</scope>
    <optional>true</optional>
</dependency>
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator </artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!-- hystrix -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
  • application.yml:
代码语言:javascript
复制
server:
  port: 8001
  
spring:
  application:
    name: cloud-provider-hystrix-payment
    
eureka:
  client:
    register-with-eureka: true 
    fetch-registry: true 
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka #eureka server
  • 启动类:
代码语言:javascript
复制
@SpringBootApplication
@EnableEurekaClient
public class PaymentHystrixMain8001 {
    public static void main(String[] args) throws Exception {
        SpringApplication.run(PaymentHystrixMain8001.class, args);
    }
}
  • service:
代码语言:javascript
复制
@Service
public class PaymentService {

    public String paymentOk(Integer id) {
        return " thats ok";
    }
    
    public String paymentError(Integer id) {
        try {
            TimeUnit.SECONDS.sleep(5);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "somethind wrong";
    }
}

这里一个方法模拟正常情况,一个方法模拟超时的情况。然后在controller中调这两个方法。

  • controller:
代码语言:javascript
复制
@RestController
@RequestMapping("/payment")
public class PaymentController {

    @Autowired
    private PaymentService paymentService;
    @Value("${server.port}")
    private String port;
    
    @GetMapping("/ok/{id}")
    public String paymentOk(@PathVariable("id") Integer id) {
        return paymentService.paymentOk(id) + "\r\n" + port;
    }
    
    @GetMapping("/error/{id}")
    public String paymentError(@PathVariable("id") Integer id) {
        return paymentService.paymentError(id) + "\r\n" + port;
    }
}

启动7001的eureka server和这个8001,访问从controller中的两个接口,测试一下。在非高并发的情况下,两个接口都可以正常返回数据,只不过paymentOk可以立即响应,而paymentError就要等待5秒才会响应。但是,如果搞个jmeter对paymentError接口进行压测,20000个线程并发去请求paymentError,然后你再用浏览器访问paymentOk,发现paymentOk也被拖慢了。如果线程再多一点儿,可能就会访问不了了。可明明是paymentError接口响应慢,paymentOk是不应该受影响的。所以可以用hystrix对服务进行降级。下面先新建一个consumer调用这个payment服务,然后再在这个consumer中对服务进行降级。

5、cloud-consumer-feign-hystrix-order80项目搭建: 新建名为cloud-consumer-feign-hystrix-order80的module。

  • pom.xml:
代码语言:javascript
复制
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-devtools</artifactId>
    <scope>runtime</scope>
    <optional>true</optional>
</dependency>
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator </artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!-- hystrix -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<!-- openfeign -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
  • yml:
代码语言:javascript
复制
server:
  port: 80
  
eureka:
  client:
    register-with-eureka: false
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka
  • 主启动类:
代码语言:javascript
复制
@SpringBootApplication
@EnableFeignClients
public class OrderHystrixMain80 {
    public static void main(String[] args) throws Exception {
        SpringApplication.run(OrderHystrixMain80.class, args);
    }
}
  • service:
代码语言:javascript
复制
@Service
@FeignClient(value = "CLOUD-PROVIDER-HYSTRIX-PAYMENT")
public interface PaymentHystrixService {
    
    @GetMapping("payment/ok/{id}")
    public String paymentOk(@PathVariable("id") Integer id);
    
    @GetMapping("payment/error/{id}")
    public String paymentError(@PathVariable("id") Integer id);
}
  • controller:
代码语言:javascript
复制
@RestController
@RequestMapping("/order")
public class OrderHystrixController {

    @Autowired
    private PaymentHystrixService phService;
    
    @GetMapping("/hystrix/ok/{id}")
    public String paymentOk(@PathVariable("id") Integer id) {
        return phService.paymentOk(id);
    }
    
    @GetMapping("/hystrix/error/{id}")
    public String paymentError(@PathVariable("id") Integer id) {
        return phService.paymentError(id);
    }
}

启动后,通过浏览器访问http://localhost/order/hystrix/ok/1,发现是立即响应的,访问http://localhost/order/hystrix/error/1发现报500了,控制台报错 Read timed out。这是因为openfeign默认超时时间是1秒,而error接口又设置了线程睡5秒。可以在order80的配置文件中配置openfeign超时时间,设置大于5秒,就可以正常访问。

代码语言:javascript
复制
ribbon:
  # 建立连接后从服务器获取可用资源的时间
  ReadTimeout: 6000
  # 建立连接所有的时间
  ConnectTimeout: 6000

这是没有并发的情况,再使用jmeter进行压测,那么这两个接口都得凉凉了。

6、如何解决上面的问题? 服务提供方payment8001:

  • 如果8001超时,不能让order80一直转圈圈等待,要进行payment8001服务降级
  • 如果8001挂掉了,也不能让order80一直等待,要进行payment8001服务降级

服务调用方order80:

  • 如果payment8001没问题,order80自己出故障了,那么order80要进行服务降级

7、payment8001服务降级配置: payment8001的paymentError方法,线程睡了5秒,所以至少5秒才会有响应。假设我们认为这个方法正常是3秒就能响应完的,超过3秒就要进行服务降级。那么我们就设置超时时间峰值为3秒,超过了3秒就要有兜底的方法。

  • 首先在启动类上加上@EnableCircuitBreaker注解激活hystrix功能;
  • 然后在paymentError方法上加上@HystrixCommand注解,并且配置超时调用的方法,如下:
代码语言:javascript
复制
@HystrixCommand(fallbackMethod = "paymentError_default", commandProperties = {
            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000")
    })
    public String paymentError(Integer id) {
        try {
            TimeUnit.SECONDS.sleep(5);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "somethind wrong";
    }
    
    public String paymentError_default(Integer id) {
        return "这是兜底的方法";
    }

这段代码的意思就是,paymentError方法至少要5秒才会响应,但是我加上了hystrix的注解,设置了最大响应时长为3秒,超过3秒,那就走兜底的方法。所以现在启动payment8001访问paymentError方法,应该会打出"这是兜底的方法"这句话。

hystrix服务降级

说明hystrix配置成功了,并且除了超时,如果paymentError报异常了,比如写一个int x = 10 / 0,也会走兜底的方法。

8、消费端order80的服务降级: 消费端服务降级也一样的配置,在主启动类上加@EnableCircuitBreaker注解,然后controller写成下面这样:

代码语言:javascript
复制
@GetMapping("/hystrix/error/{id}")
@HystrixCommand(fallbackMethod = "paymentError_default", commandProperties = {
        @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000")
})
public String paymentError(@PathVariable("id") Integer id) {
    return phService.paymentError(id);
}
    
public String paymentError_default(@PathVariable("id")Integer id) {
    return "这是消费端兜底的方法";
}

配置超过3秒就走兜底的方法。而服务端payment8001对应的方法设置了线程睡5秒,超过了3秒才会有响应,所以这里会走兜底的方法。注意ribbon默认超时时间是1秒,所以如果修改ribbon超时时间的话,即使payment8001中设置线程睡2秒,order80中hystrix配置超时时间3秒,也会走兜底的方法,因为是否超时优先取的是ribbon配置的。

9、全局降级配置: 上面针对需要服务降级的两个方法加上了hystrix相关配置,如果还有大量的方法也需要服务降级,在每个方法上都加上这么一段注解,不太方便,所以就出现了全局降级配置。比如要在order80上做全局服务降级配置,只需要将controller改成下面这样即可:

代码语言:javascript
复制
@RestController
@RequestMapping("/order")
@DefaultProperties(defaultFallback = "defaultMethod", commandProperties = {
        @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000")
})
public class OrderHystrixController {

    @Autowired
    private PaymentHystrixService phService;
    
    @GetMapping("/hystrix/ok/{id}")
    @HystrixCommand
    public String paymentOk(@PathVariable("id") Integer id) {
        return phService.paymentOk(id);
    }
    
    @GetMapping("/hystrix/error/{id}")
    @HystrixCommand(fallbackMethod = "paymentError_default", commandProperties = {
            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000")
    })
    public String paymentError(@PathVariable("id") Integer id) {
        return phService.paymentError(id);
    }
    
    public String paymentError_default(@PathVariable("id")Integer id) {
        return "这是消费端兜底的方法";
    }
    
    public String defaultMethod() {
        return "我是全局默认的服务降级配置";
    }
}

首先在类上加注解,并配置超时时间,然后需要用全局降级的方法上加@HystrixCommand注解。这里用paymentOk方法来演示,payment8001端的paymentOk方法也设置线程睡4秒钟,paymentOk方法应该会打印出“我是全局默认的服务降级配置”这句话。

全局降级配置

然后将payment8001的paymentOk方法改成睡2秒钟,那么就会正常返回:

正常访问

然后paymentError方法,因为在方法上配置了hystrix相关配置,所以还是走方法对应的配置,而不是走全局。

但是以上做法还是不够完美,因为order80调用payment8001,所有接口都是通过openfeign去调用的,擒贼先擒王,所以最好的做法就是在openfeign调用payment8001的接口中添加实现去做降级。具体做法如下:

  • 修改yml:
代码语言:javascript
复制
feign:
  hystrix:
    enabled: true
  • order80的service改成这样:
代码语言:javascript
复制
@Service
@FeignClient(value = "CLOUD-PROVIDER-HYSTRIX-PAYMENT", fallback = PaymentHystrixServiceImpl.class)
public interface PaymentHystrixService {
    
    @GetMapping("payment/ok/{id}")
    public String paymentOk(@PathVariable("id") Integer id);
    
    @GetMapping("payment/error/{id}")
    public String paymentError(@PathVariable("id") Integer id);
}
  • 新建service的实现:
代码语言:javascript
复制
@Component
public class PaymentHystrixServiceImpl implements PaymentHystrixService{

    @Override
    public String paymentOk(Integer id) {
        return "paymentOk-default-return";
    }

    @Override
    public String paymentError(Integer id) {
        return "paymentError-default-return";
    }

}
  • 最后把controller中hystrix相关注解都去掉。

这样就搞定了,当访问8001发生异常、或者8001压根儿就没启动时,就会执行serviceImpl里面的方法。

10、服务熔断: 当微服务调用链路的某个服务不可用了或者响应时间太长了,会对服务进行降级,快速返回友好的响应信息,当检测到该节点正常了之后,又会恢复调用。即一开始是close状态,检测到异常就变成open状态,然后再变成half open状态,恢复一部分调用,如果没问题再变成close。下面就演示服务熔断。

  • 首先在payment8001的service中加如下代码:
代码语言:javascript
复制
@HystrixCommand(fallbackMethod = "paymentCircuitBreaker_fallback", commandProperties = {
            @HystrixProperty(name = "circuitBreaker.enabled", value = "true"), // 是否开启断路器
            @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "10"), // 请求次数
            @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "10000"), // 时间窗口期
            @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "60"), // 失败率达到多少后跳闸
            // 10次请求有6次是失败的,就进行服务熔断,10秒后会变为half open状态,看看能否请求成功,如果成功就变成close状态
    })
    public String paymentCircuitBreaker(Integer id) {
        if (id < 0) {
            throw new RuntimeException("id不能为负数");
        }
        return "调用成功";
    }
    
    public String paymentCircuitBreaker_fallback(Integer id) {
        return "id不能为负数";
    }

这几个注解的意思就是在10次访问中,如果失败了6次,那就熔断,返回“id不能为负数这句话”,这个时候,即使你传的id是正数,也会返回这句话,因为这个时候服务熔断了。10000 milliseconds后,会变成半开状态,试着放行一个请求,如果此时你请求的id是正数,那么就返回“调用成功”,并且解除熔断。

  • 在controller中新增如下方法:
代码语言:javascript
复制
@GetMapping("/breaker/{id}")
    public String paymentCircuitBreaker(@PathVariable("id") Integer id) {
        return paymentService.paymentCircuitBreaker(id);
    }

可以访问该接口,先传入负数id,然后满足10次有6次失败的情况下,再将id变为正数传入,发现也是返回“id不能为负数”这句话。过一段时间后才恢复正常,说明服务熔断起作用了。

11、hystrix的图形化界面:

  • 新建一个cloud-consumer-hystrix-dashboard9001的module
  • pom.xml:
代码语言:javascript
复制
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-devtools</artifactId>
    <scope>runtime</scope>
    <optional>true</optional>
</dependency>
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator </artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-netflix-hystrix-dashboard -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>
  • 主启动类:
代码语言:javascript
复制
@SpringBootApplication
@EnableHystrixDashboard
public class HystrixDashBoardMain9001 {

    public static void main(String[] args) throws Exception {
        SpringApplication.run(HystrixDashBoardMain9001.class, args);
    }
}
  • 如果要监控8001,那么需要在8001中配置如下bean:
代码语言:javascript
复制
@Configuration
public class DashBoardConfig {

    @Bean
    public ServletRegistrationBean<HystrixMetricsStreamServlet> getBean() {
        HystrixMetricsStreamServlet bean = new HystrixMetricsStreamServlet();
        ServletRegistrationBean<HystrixMetricsStreamServlet> register = new ServletRegistrationBean<HystrixMetricsStreamServlet>(bean);
        register.setLoadOnStartup(1);
        register.addUrlMappings("/hystrix.stream");
        register.setName("HystrixMetricsStreamServlet");
        return register;
    }
}
  • 然后访问 localhost:9001/hystrix,在页面中填写如下信息:

dashboard 填好后回车,然后再去访问8001,那么8001的访问信息就会出现在dashboard中了。

dashboard

二、服务网关之spring gateway

1、服务网关是来干嘛的? 一般来说,用户访问首先是到nginx,nginx会做负载均衡,然后并不是直接访问各位微服务应用,而是先到gateway。gateway可以做路由转发、权限校验、流量控制等。功能类似的框架还有zuul和zuul2,zuul停更了,zuul2还没完善出来,所以spring自己搞了一套gateway。

2、gateway核心概念:

  • 路由Route:简单的理解为url,如果断言为true就匹配该url
  • 断言Predicate:路由转发的判断条件
  • 过滤Filter:过滤器

3、gateway工作流程: 核心逻辑是路由转发 + 执行过滤链。客户端向gateway发请求,然后在gateway handler mapping 找到相匹配的路由,将请求发送到gateway web handler,handler再通过过滤链将请求发送到微服务中,然后返回。

4、代码演示:

  • 新建名为cloud-gateway-gateway9527的module;
  • pom.xml:
代码语言:javascript
复制
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-devtools</artifactId>
    <scope>runtime</scope>
    <optional>true</optional>
</dependency>
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
</dependency>
<!-- eureka client -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!-- gateway -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
  • yml:
代码语言:javascript
复制
server:
  port: 9527
  
spring:
  application:
    name: cloud-gateway
    
eureka:
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url:
       defaultZone: http://eureka7001.com:7001/eureka
  instance:
    instance-id: cloud-gateway
    prefer-ip-address: true
  • 主启动:
代码语言:javascript
复制
@SpringBootApplication
@EnableEurekaClient
public class GatewayMain9527 {
    public static void main(String[] args) throws Exception {
        SpringApplication.run(GatewayMain9527.class, args);
    }
}

8001的controller中有两个接口,现在我们可以直接通过接口路由访问到,但是我不想暴露8001端口,想通过9527端口去访问,做法如下:

  • 将9527的yml改成下面这样:
代码语言:javascript
复制
server:
  port: 9527
  
spring:
  application:
    name: cloud-gateway
  cloud:
    gateway:
      routes:
      - id: payment_route # id,要求唯一
        uri: http://localhost:8001 #提供服务的路由地址
        predicates:
        - Path=/payment/ok/** # 路径匹配的进行路由
        
      - id: payment_route # id,要求唯一
        uri: http://localhost:8001 #提供服务的路由地址
        predicates:
        - Path=/payment/error/** # 路径匹配的进行路由
          
    
eureka:
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url:
       defaultZone: http://eureka7001.com:7001/eureka
  instance:
    instance-id: cloud-gateway
    prefer-ip-address: true

现在依次启动7001的eureka、8001的payment和9527的gateway,然后访问呢localhost:9527/payment/ok/1,发现可以访问成功,说明路由转发成功。 这是配置网关的第一种方式,还有硬编码的方式,如下:

代码语言:javascript
复制
@Configuration
public class GatewayConfig {
    @Bean
    public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
        RouteLocatorBuilder.Builder routes = builder.routes();
        // 意思就是访问localhost:9527/domestic将会转发到https://tuijian.hao123.com/domestic中去
        routes.route("path_id", r -> r.path("/domestic").uri("https://tuijian.hao123.com/domestic")).build();
        return routes.build();
    }
}

现在访问localhost:9527/domestic,结果如下:

gateway路由转发

5、动态路由: 提供payment服务的有8001和8002,但是上面那样配置只写了8001,现在要实现通过微服务名称来做动态路由。即在配置那里不写死8001或8002,而是写8001和8002的微服务名称,这样就可以实现动态路由。

  • 首先确保启动了8001和8002;
  • 改yml:
代码语言:javascript
复制
server:
  port: 9527
  
spring:
  application:
    name: cloud-gateway
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true # 开启从注册中心动态创建路由的功能
      routes:
      - id: payment_route1 # id,要求唯一
        #uri: http://localhost:8001 #提供服务的路由地址
        uri: lb://CLOUD-PAYMENT-SERVICE #微服务名称
        predicates:
        - Path=/payment/** # 路径匹配的进行路由
        
      - id: payment_route2 # id,要求唯一
        #uri: http://localhost:8001 #提供服务的路由地址
        uri: lb://CLOUD-PAYMENT-SERVICE #微服务名称
        predicates:
        - Path=/payment/** # 路径匹配的进行路由
          
    
eureka:
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url:
       defaultZone: http://eureka7001.com:7001/eureka
  instance:
    instance-id: cloud-gateway
    prefer-ip-address: true

就这样就行了,然后访问http://localhost:9527/payment/1,就可以成功访问到8001和8002,并且会进行负载均衡,一次8001,一次8002,轮着来。

6、常用断言:

代码语言:javascript
复制
 predicates:
 - Path=/payment/** # 路径匹配的进行路由
 - After=2020-05-04T20:47:11.281+08:00[Asia/Shanghai] # 配置的规则要在2020年5月4日20点20分后才生效,有after就有before和between
 - Cookie=username,test # 必须带cookie访问,cookie名叫username,值为test,值也可以写正则表达式
 - Header=X-Request-Id,\d+ # 必须带请求头访问,请求头名为X-Request-Id,值要满足 \d+ 这个正则表达式
 - Host=**.somehost.com,**.otherhost.com #请求域名必须匹配这两个,即请求时添加header,名为host,值匹配这两个即可
 - Method=GET #必须是get请求
 - Query=id,\d+ #必须有名为id的参数且值匹配 \d+ 这个正则

7、常用filter: filter生命周期有两种,一种是在业务逻辑之前,一种是在业务逻辑之后;种类也是两种,一种gatewayFilter,一种globalFilter。用法和predicates一样,比如:

代码语言:javascript
复制
filters:
- AddRequestParameter=X-Request-Id,1024 # 请求必须带名为X-Request-Id的请求头,值为1024

8、自定义过滤器: 可以实现全局日志记录,统一网关鉴权等功能。

  • 新建自定义过滤器类:
代码语言:javascript
复制
@Component
@Slf4j
public class MyFilter implements GlobalFilter, Ordered{
    /**
     * 表示这个过滤器的优先级,数字越小优先级越高
     */
    @Override
    public int getOrder() {
        return 0;
    }

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        log.info("=================进去自定义全局过滤器=============");
        // 获取id参数
        String id = exchange.getRequest().getQueryParams().getFirst("id");
        if (!"1".equals(id)) {
            log.error("================= id不存在==================");
            // 设置返回码
            exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
            return exchange.getResponse().setComplete();
        }
        return chain.filter(exchange);
    }
}

也就是说,如果没有id这个参数或者id参数值不为1的,都会被拦截。实际生产中可以用这个来验证请求是否携带token。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、服务降级&熔断&限流之Hystrix(豪猪)
  • 二、服务网关之spring gateway
相关产品与服务
负载均衡
负载均衡(Cloud Load Balancer,CLB)提供安全快捷的流量分发服务,访问流量经由 CLB 可以自动分配到云中的多台后端服务器上,扩展系统的服务能力并消除单点故障。负载均衡支持亿级连接和千万级并发,可轻松应对大流量访问,满足业务需求。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档