spring cloud 2
1服务调用组件Feign
1.1概述
- Feign 是一个声明式的 REST 客户端,它用了基于接口的注解方式,很方便实现客户端配置。
- Feign 最初由 Netflix 公司提供,但不支持SpringMVC注解,后由 SpringCloud 对其封装,支持了SpringMVC注解,让使用者更易于接受。
1.2快速入门
在消费端引入 open-feign 依赖
1 2 3 4
| <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>
|
编写Feign调用接口。复制粘贴被调方的conreoller方法,加上类路径。
GoodsFeignClient
1 2 3 4 5 6 7
| @FeignClient(value = "FEIGN-PROVIDER") public interface GoodsFeignClient {
@GetMapping("/goods/findOne/{id}") public Goods findGoodsById(@PathVariable("id") int id);
}
|
在启动类 添加 @EnableFeignClients 注解,开启Feign功能
测试调用
OrderController
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| package com.itheima.consumer.controller;
import com.itheima.consumer.domain.Goods; import com.itheima.consumer.feign.GoodsFeignClient; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate;
@RestController @RequestMapping("/order") public class OrderController {
@Autowired private RestTemplate restTemplate;
@Autowired private GoodsFeignClient goodsFeignClient;
@GetMapping("/goods/{id}") public Goods findGoodsById(@PathVariable("id") int id){
Goods goods = goodsFeignClient.findGoodsById(id);
return goods; }
}
|
1.3其他设置
1.3.1超时设置
• Feign 底层依赖于 Ribbon 实现负载均衡和远程调用。
• Ribbon默认1秒超时。
• 超时配置: yml中
1 2 3 4
| ribbon: ConnectTimeout: 1000 ReadTimeout: 3000
|
1.3.2日志记录(xml和配置类都需要)
• Feign 只能记录 debug 级别的日志信息。
1 2 3 4
| logging: level: com.itheima: debug
|
• 定义Feign日志级别Bean
FeignLogConfig
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| package com.itheima.consumer.config;
import feign.Logger; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration;
@Configuration public class FeignLogConfig {
@Bean public Logger.Level level(){ return Logger.Level.FULL; } }
|
• 启用该Bean:
GoodsFeignClient(定义的接口)
1
| @FeignClient(value = "FEIGN-PROVIDER",configuration = FeignLogConfig.class)
|
2熔断器Hystrix 保险丝
2.1概述
Hystix 是 Netflix 开源的一个延迟和容错库,用于隔离访问远程服务、第三方库,防止出现级联失败(服务雪崩)。
雪崩:一个服务失败,导致整条链路的服务都失败的情形。
Hystix 主要功能
隔离 面试
线程池隔离
2.信号量隔离
降级:异常,超时
熔断
限流
2.2服务降级
服务提供方
在服务提供方,引入 hystrix 依赖
1 2 3 4 5
| <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> </dependency>
|
定义降级方法
1 2 3 4 5 6 7 8 9 10 11
|
public Goods findOne_fallback(int id){ Goods goods = new Goods(); goods.setTitle("降级了~~~");
return goods; }
|
使用 @HystrixCommand 注解配置降级方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| @GetMapping("/findOne/{id}") @HystrixCommand(fallbackMethod = "findOne_fallback",commandProperties = { //设置Hystrix的超时时间,默认1s @HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value = "3000") }) public Goods findOne(@PathVariable("id") int id){
int i = 3/0; try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } Goods goods = goodsService.findOne(id);
goods.setTitle(goods.getTitle() + ":" + port); return goods; }
|
在启动类上开启Hystrix功能:@EnableCircuitBreaker
服务消费方
feign 组件已经集成了 hystrix 组件。
定义feign 调用接口实现类,复写方法,即 降级方法
GoodsFeignClientFallback
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| package com.itheima.consumer.feign;
import com.itheima.consumer.domain.Goods; import org.springframework.stereotype.Component;
@Component public class GoodsFeignClientFallback implements GoodsFeignClient { @Override public Goods findGoodsById(int id) { Goods goods = new Goods(); goods.setTitle("又被降级了~~~"); return goods; } }
|
在 @FeignClient 注解中使用 fallback 属性设置降级处理类。
GoodsFeignClient
1 2 3 4 5 6 7 8
| @FeignClient(value = "HYSTRIX-PROVIDER",fallback = GoodsFeignClientFallback.class) public interface GoodsFeignClient {
@GetMapping("/goods/findOne/{id}") public Goods findGoodsById(@PathVariable("id") int id);
}
|
配置开启
1 2 3 4
| # 开启feign对hystrix的支持 feign: hystrix: enabled: true
|
2.3熔断 保险丝
Hyst rix 熔断机制,用于监控微服务调用情况,当失败的情况达到预定的阈值(5秒失败20次),会打开断路器,拒绝所有请求,直到服务恢复正常为止。
1 2 3
| circuitBreaker.sleepWindowInMilliseconds:保险丝打开后 进入半开状态的监控时间 circuitBreaker.requestVolumeThreshold:失败次数 circuitBreaker.errorThresholdPercentage:失败率
|
提供者controller中
1 2 3 4 5 6 7 8 9 10 11
| @HystrixCommand(fallbackMethod = "findOne_fallback",commandProperties = { //设置Hystrix的超时时间,默认1s @HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value = "3000"), //监控时间 默认5000 毫秒 @HystrixProperty(name="circuitBreaker.sleepWindowInMilliseconds",value = "5000"), //失败次数。默认20次 @HystrixProperty(name="circuitBreaker.requestVolumeThreshold",value = "20"), //失败率 默认50% @HystrixProperty(name="circuitBreaker.errorThresholdPercentage",value = "50")
})
|
2.4熔断监控-运维
Hystrix 提供了 Hystrix-dashboard 功能,用于实时监控微服务运行状态。
但是Hystrix-dashboard只能监控一个微服务。
Netflix 还提供了 Turbine ,进行聚合监控。
Turbine聚合监控
一、搭建监控模块
1. 创建监控模块
创建hystrix-monitor模块,使用Turbine聚合监控多个Hystrix dashboard功能,
2. 引入Turbine聚合监控起步依赖
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
| <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>hystrix-parent</artifactId> <groupId>com.itheima</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion>
<artifactId>hystrix-monitor</artifactId> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> </properties>
<dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId> </dependency>
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-turbine</artifactId> </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>
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies>
<build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build>
</project>
|
3. 修改application.yml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| spring: application.name: hystrix-monitor server: port: 8769 turbine: combine-host-port: true app-config: hystrix-provider,hystrix-consumer cluster-name-expression: "'default'" aggregator: cluster-config: default eureka: client: serviceUrl: defaultZone: http://localhost:8761/eureka/
|
4. 创建启动类
1 2 3 4 5 6 7 8 9 10 11 12 13
| @SpringBootApplication @EnableEurekaClient
@EnableTurbine @EnableHystrixDashboard public class HystrixMonitorApp {
public static void main(String[] args) { SpringApplication.run(HystrixMonitorApp.class, args); }
}
|
二、修改被监控模块
需要分别修改 hystrix-provider 和 hystrix-consumer 模块:
1、导入依赖:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency>
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> </dependency>
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId> </dependency>
|
2、配置Bean
此处为了方便,将其配置在启动类中。
1 2 3 4 5 6 7 8 9
| @Bean public ServletRegistrationBean getServlet() { HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet(); ServletRegistrationBean registrationBean = new ServletRegistrationBean(streamServlet); registrationBean.setLoadOnStartup(1); registrationBean.addUrlMappings("/actuator/hystrix.stream"); registrationBean.setName("HystrixMetricsStreamServlet"); return registrationBean; }
|
3、启动类上添加注解@EnableHystrixDashboard
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| @EnableDiscoveryClient @EnableEurekaClient @SpringBootApplication @EnableFeignClients @EnableHystrixDashboard public class ConsumerApp {
public static void main(String[] args) { SpringApplication.run(ConsumerApp.class,args); } @Bean public ServletRegistrationBean getServlet() { HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet(); ServletRegistrationBean registrationBean = new ServletRegistrationBean(streamServlet); registrationBean.setLoadOnStartup(1); registrationBean.addUrlMappings("/actuator/hystrix.stream"); registrationBean.setName("HystrixMetricsStreamServlet"); return registrationBean; } }
|
三、启动测试
1、启动服务:
eureka-server
hystrix-provider
hystrix-consumer
hystrix-monitor
2、访问:
在浏览器访问http://localhost:8769/hystrix/ 进入Hystrix Dashboard界面
界面中输入监控的Url地址 http://localhost:8769/turbine.stream,监控时间间隔2000毫秒和title,如下图
- 实心圆:它有颜色和大小之分,分别代表实例的监控程度和流量大小。如上图所示,它的健康度从绿色、黄色、橙色、红色递减。通过该实心圆的展示,我们就可以在大量的实例中快速的发现故障实例和高压力实例。
- 曲线:用来记录 2 分钟内流量的相对变化,我们可以通过它来观察到流量的上升和下降趋势。
3网关gateway 路由+过滤
3.1概述
切面
• 网关旨在为微服务架构提供一种简单而有效的统一的API路由管理方式。
• 在微服务架构中,不同的微服务可以有不同的网络地址,各个微服务之间通过互相调用完成用户请求,客户端可能通过调用N个微服务的接口完成一个用户请求。
1 2 3 4
| 存在的问题: 客户端多次请求不同的微服务,增加客户端的复杂性 认证复杂,每个服务都要进行认证 http请求不同服务次数增加,性能不高
|
• 网关就是系统的入口,封装了应用程序的内部结构,为客户端提供统一服务,一些与业务本身功能无关的公共逻辑可以在这里实现,诸如认证、鉴权、监控、缓存、负载均衡、流量管控、路由转发等
• 在目前的网关解决方案里,有Nginx+ Lua、Netflix Zuul 、Spring Cloud Gateway等等
3.2快速入门
搭建网关模块 api-gateway-server
引入依赖:starter-gateway
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>gateway-parent</artifactId> <groupId>com.itheima</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion>
<artifactId>api-gateway-server</artifactId>
<dependencies>
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency>
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> </dependencies>
</project>
|
编写启动类
ApiGatewayApp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| package com.itheima.gateway;
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@SpringBootApplication @EnableEurekaClient public class ApiGatewayApp {
public static void main(String[] args) { SpringApplication.run(ApiGatewayApp.class,args); }
}
|
编写配置文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| server: port: 80 #服务端口号
spring: application: name: api-gateway-server #服务名称
cloud: # 网关配置 gateway: # 路由配置:转发规则 routes: #集合。 # id: 唯一标识。默认是一个UUID # uri: 转发路径 # predicates: 条件,用于请求网关路径的匹配规则 # filters:配置局部过滤器的
- id: gateway-provider # 静态路由 # uri: http://localhost:8001/ # 动态路由 uri: lb://eureka-provider #路由的路径 predicates: - Path=/goods/** - id: gateway-consumer # uri: http://localhost:9000 uri: lb://eureka-consumer predicates: - Path=/order/**
#注册到哪个注册中心 eureka: client: service-url: defaultZone: http://localhost:8761/eureka
|
启动测试
3.3静态路由
1
| uri: http://localhost:8001/
|
3.4动态路由
3.4.2修改cloud网管里的动态路由uri属性:uri: lb://服务名称
1
| uri: lb://GATEWAY-PROVIDER
|
3.4.2引入eureka-client配置
pom
1 2 3 4
| <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency>
|
yml
1 2 3 4
| eureka: client: service-url: defaultZone: http://localhost:8761/eureka
|
3.5微服务名称配置 了解
1 2 3 4 5 6 7 8 9
| spring: cloud: # 网关配置 gateway: # 微服务名称配置 discovery: locator: enabled: true # 设置为true 请求路径前可以添加微服务名称 lower-case-service-id: true # 允许为小写
|
3.6过滤器
内置过滤器 自定义过滤器
局部过滤器 全局过滤器
1内置局部过滤器
2内置全局过滤器
3自定义局部过滤器 难
4自定义全局过滤器
内置过滤器 局部过滤器:
1 2 3 4 5 6 7 8
| - id: gateway-provider #uri: http://localhost:8001/ uri: lb://GATEWAY-PROVIDER predicates: - Path=/goods/** #过滤器 filters: - AddResponseHeader=foo, bar
|
内置过滤器 全局过滤器: route同级
1 2
| default-filters: - AddResponseHeader=xiqinling,lizhiyong
|
拓展:
内置的过滤器工厂
这里简单将Spring Cloud Gateway内置的所有过滤器工厂整理成了一张表格。如下:
过滤器工厂 | 作用 | 参数 |
---|
AddRequestHeader | 为原始请求添加Header | Header的名称及值 |
AddRequestParameter | 为原始请求添加请求参数 | 参数名称及值 |
AddResponseHeader | 为原始响应添加Header | Header的名称及值 |
DedupeResponseHeader | 剔除响应头中重复的值 | 需要去重的Header名称及去重策略 |
Hystrix | 为路由引入Hystrix的断路器保护 | HystrixCommand 的名称 |
FallbackHeaders | 为fallbackUri的请求头中添加具体的异常信息 | Header的名称 |
PrefixPath | 为原始请求路径添加前缀 | 前缀路径 |
PreserveHostHeader | 为请求添加一个preserveHostHeader=true的属性,路由过滤器会检查该属性以决定是否要发送原始的Host | 无 |
RequestRateLimiter | 用于对请求限流,限流算法为令牌桶 | keyResolver、rateLimiter、statusCode、denyEmptyKey、emptyKeyStatus |
RedirectTo | 将原始请求重定向到指定的URL | http状态码及重定向的url |
RemoveHopByHopHeadersFilter | 为原始请求删除IETF组织规定的一系列Header | 默认就会启用,可以通过配置指定仅删除哪些Header |
RemoveRequestHeader | 为原始请求删除某个Header | Header名称 |
RemoveResponseHeader | 为原始响应删除某个Header | Header名称 |
RewritePath | 重写原始的请求路径 | 原始路径正则表达式以及重写后路径的正则表达式 |
RewriteResponseHeader | 重写原始响应中的某个Header | Header名称,值的正则表达式,重写后的值 |
SaveSession | 在转发请求之前,强制执行WebSession::save 操作 | 无 |
secureHeaders | 为原始响应添加一系列起安全作用的响应头 | 无,支持修改这些安全响应头的值 |
SetPath | 修改原始的请求路径 | 修改后的路径 |
SetResponseHeader | 修改原始响应中某个Header的值 | Header名称,修改后的值 |
SetStatus | 修改原始响应的状态码 | HTTP 状态码,可以是数字,也可以是字符串 |
StripPrefix | 用于截断原始请求的路径 | 使用数字表示要截断的路径的数量 |
Retry | 针对不同的响应进行重试 | retries、statuses、methods、series |
RequestSize | 设置允许接收最大请求包的大小。如果请求包大小超过设置的值,则返回 413 Payload Too Large | 请求包大小,单位为字节,默认值为5M |
ModifyRequestBody | 在转发请求之前修改原始请求体内容 | 修改后的请求体内容 |
ModifyResponseBody | 修改原始响应体的内容 | 修改后的响应体内容 |
Default | 为所有路由添加过滤器 | 过滤器工厂名称及值 |
Tips:每个过滤器工厂都对应一个实现类,并且这些类的名称必须以GatewayFilterFactory
结尾,这是Spring Cloud Gateway的一个约定,例如AddRequestHeader
对应的实现类为AddRequestHeaderGatewayFilterFactory
。
1、AddRequestHeader GatewayFilter Factory
为原始请求添加Header,配置示例:
1 2 3 4 5 6 7 8
| spring: cloud: gateway: routes: - id: add_request_header_route uri: https://example.org filters: - AddRequestHeader=X-Request-Foo, Bar
|
为原始请求添加名为 X-Request-Foo
,值为 Bar
的请求头
2、AddRequestParameter GatewayFilter Factory
为原始请求添加请求参数及值,配置示例:
1 2 3 4 5 6 7 8
| spring: cloud: gateway: routes: - id: add_request_parameter_route uri: https://example.org filters: - AddRequestParameter=foo, bar
|
为原始请求添加名为foo,值为bar的参数,即:foo=bar
3、AddResponseHeader GatewayFilter Factory
为原始响应添加Header,配置示例:
1 2 3 4 5 6 7 8
| spring: cloud: gateway: routes: - id: add_response_header_route uri: https://example.org filters: - AddResponseHeader=X-Response-Foo, Bar
|
为原始响应添加名为 X-Request-Foo
,值为 Bar
的响应头
4、DedupeResponseHeader GatewayFilter Factory
DedupeResponseHeader可以根据配置的Header名称及去重策略剔除响应头中重复的值,这是Spring Cloud Greenwich SR2提供的新特性,低于这个版本无法使用。
我们在Gateway以及微服务上都设置了CORS(解决跨域)Header的话,如果不做任何配置,那么请求 -> 网关 -> 微服务,获得的CORS Header的值,就将会是这样的:
1 2
| Access-Control-Allow-Credentials: true, true Access-Control-Allow-Origin: https://musk.mars, https://musk.mars
|
可以看到这两个Header的值都重复了,若想把这两个Header的值去重的话,就需要使用到DedupeResponseHeader,配置示例:
1 2 3 4 5 6 7 8 9
| spring: cloud: gateway: routes: - id: dedupe_response_header_route uri: https://example.org filters: - DedupeResponseHeader=Access-Control-Allow-Credentials Access-Control-Allow-Origin
|
去重策略:
- RETAIN_FIRST:默认值,保留第一个值
- RETAIN_LAST:保留最后一个值
- RETAIN_UNIQUE:保留所有唯一值,以它们第一次出现的顺序保留
若想对该过滤器工厂有个比较全面的了解的话,建议阅读该过滤器工厂的源码,因为源码里有详细的注释及示例,比官方文档写得还好:org.springframework.cloud.gateway.filter.factory.DedupeResponseHeaderGatewayFilterFactory
5、Hystrix GatewayFilter Factory
为路由引入Hystrix的断路器保护,配置示例:
1 2 3 4 5 6 7 8
| spring: cloud: gateway: routes: - id: hystrix_route uri: https://example.org filters: - Hystrix=myCommandName
|
Hystrix是Spring Cloud第一代容错组件,不过已经进入维护模式,未来Hystrix会被Spring Cloud移除掉,取而代之的是Alibaba Sentinel/Resilience4J。所以本文不做详细介绍了,感兴趣的话可以参考官方文档:
6、FallbackHeaders GatewayFilter Factory
同样是对Hystrix的支持,上一小节所介绍的过滤器工厂支持一个配置参数:fallbackUri
,该配置用于当发生异常时将请求转发到一个特定的uri上。而FallbackHeaders
这个过滤工厂可以在转发请求到该uri时添加一个Header,这个Header的值为具体的异常信息。配置示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| spring: cloud: gateway: routes: - id: ingredients uri: lb://ingredients predicates: - Path=//ingredients/** filters: - name: Hystrix args: name: fetchIngredients fallbackUri: forward:/fallback - id: ingredients-fallback uri: http://localhost:9994 predicates: - Path=/fallback filters: - name: FallbackHeaders args: executionExceptionTypeHeaderName: Test-Header
|
这里也不做详细介绍了,感兴趣可以参考官方文档:
7、PrefixPath GatewayFilter Factory
为原始的请求路径添加一个前缀路径,配置示例:
1 2 3 4 5 6 7 8
| spring: cloud: gateway: routes: - id: prefixpath_route uri: https://example.org filters: - PrefixPath=/mypath
|
该配置使访问${GATEWAY_URL}/hello
会转发到https://example.org/mypath/hello
8、PreserveHostHeader GatewayFilter Factory
为请求添加一个preserveHostHeader=true的属性,路由过滤器会检查该属性以决定是否要发送原始的Host Header。配置示例:
1 2 3 4 5 6 7 8
| spring: cloud: gateway: routes: - id: preserve_host_route uri: https://example.org filters: - PreserveHostHeader
|
如果不设置,那么名为 Host
的Header将由Http Client控制
9、RequestRateLimiter GatewayFilter Factory
用于对请求进行限流,限流算法为令牌桶。配置示例:
1 2 3 4 5 6 7 8 9 10 11
| spring: cloud: gateway: routes: - id: requestratelimiter_route uri: https://example.org filters: - name: RequestRateLimiter args: redis-rate-limiter.replenishRate: 10 redis-rate-limiter.burstCapacity: 20
|
由于另一篇文章中已经介绍过如何使用该过滤器工厂实现网关限流,所以这里就不再赘述了:
或者参考官方文档:
10、RedirectTo GatewayFilter Factory
将原始请求重定向到指定的Url,配置示例:
1 2 3 4 5 6 7 8
| spring: cloud: gateway: routes: - id: redirect_route uri: https://example.org filters: - RedirectTo=302, https://acme.org
|
该配置使访问 ${GATEWAY_URL}/hello
会被重定向到 https://acme.org/hello
,并且携带一个 Location:http://acme.org
的Header,而返回客户端的HTTP状态码为302
注意事项:
- HTTP状态码应为3xx,例如301
- URL必须是合法的URL,该URL会作为
Location
Header的值
11、RemoveHopByHopHeadersFilter GatewayFilter Factory
为原始请求删除IETF组织规定的一系列Header,默认删除的Header如下:
- Connection
- Keep-Alive
- Proxy-Authenticate
- Proxy-Authorization
- TE
- Trailer
- Transfer-Encoding
- Upgrade
可以通过配置去指定仅删除哪些Header,配置示例:
1 2 3 4 5 6 7
| spring: cloud: gateway: filter: remove-hop-by-hop: headers: Connection,Keep-Alive
|
12、RemoveRequestHeader GatewayFilter Factory
为原始请求删除某个Header,配置示例:
1 2 3 4 5 6 7 8
| spring: cloud: gateway: routes: - id: removerequestheader_route uri: https://example.org filters: - RemoveRequestHeader=X-Request-Foo
|
删除原始请求中名为 X-Request-Foo
的请求头
13、RemoveResponseHeader GatewayFilter Factory
为原始响应删除某个Header,配置示例:
1 2 3 4 5 6 7 8
| spring: cloud: gateway: routes: - id: removeresponseheader_route uri: https://example.org filters: - RemoveResponseHeader=X-Response-Foo
|
删除原始响应中名为 X-Request-Foo
的响应头
14、RewritePath GatewayFilter Factory
通过正则表达式重写原始的请求路径,配置示例:
1 2 3 4 5 6 7 8 9 10 11 12
| spring: cloud: gateway: routes: - id: rewritepath_route uri: https://example.org predicates: - Path=/foo/** filters: - RewritePath=/foo/(?<segment>.*), /$\{segment}
|
该配置使得访问 /foo/bar
时,会将路径重写为/bar
再进行转发,也就是会转发到 https://example.org/bar
。需要注意的是:由于YAML语法,需用$\
替换 $
15、RewriteResponseHeader GatewayFilter Factory
重写原始响应中的某个Header,配置示例:
1 2 3 4 5 6 7 8 9 10
| spring: cloud: gateway: routes: - id: rewriteresponseheader_route uri: https://example.org filters: - RewriteResponseHeader=X-Response-Foo, password=[^&]+, password=***
|
该配置的意义在于:如果响应头中 X-Response-Foo
的值为/42?user=ford&password=omg!what&flag=true
,那么就会被按照配置的值重写成/42?user=ford&password=***&flag=true
,也就是把其中的password=omg!what
重写成了password=***
16、SaveSession GatewayFilter Factory
在转发请求之前,强制执行WebSession::save
操作,配置示例:
1 2 3 4 5 6 7 8 9 10 11
| spring: cloud: gateway: routes: - id: save_session uri: https://example.org predicates: - Path=/foo/** filters: - SaveSession
|
主要用在那种像 Spring Session 延迟数据存储(数据不是立刻持久化)的,并希望在请求转发前确保session状态保存情况。如果你将Spring Secutiry于Spring Session集成使用,并想确保安全信息都传到下游机器,你就需要配置这个filter。
17、secureHeaders GatewayFilter Factory
secureHeaders过滤器工厂主要是参考了这篇博客中的建议,为原始响应添加了一系列起安全作用的响应头。默认会添加如下Headers(包括值):
X-Xss-Protection:1; mode=block
Strict-Transport-Security:max-age=631138519
X-Frame-Options:DENY
X-Content-Type-Options:nosniff
Referrer-Policy:no-referrer
Content-Security-Policy:default-src 'self' https:; font-src 'self' https: data:; img-src 'self' https: data:; object-src 'none'; script-src https:; style-src 'self' https: 'unsafe-inline'
X-Download-Options:noopen
X-Permitted-Cross-Domain-Policies:none
如果你想修改这些Header的值,那么就需要使用这些Headers对应的后缀,如下:
xss-protection-header
strict-transport-security
frame-options
content-type-options
referrer-policy
content-security-policy
download-options
permitted-cross-domain-policies
配置示例:
1 2 3 4 5 6 7
| spring: cloud: gateway: filter: secure-headers: xss-protection-header: 2; mode=unblock
|
如果想禁用某些Header,可使用如下配置:
1 2 3 4 5 6 7 8
| spring: cloud: gateway: filter: secure-headers: disable: frame-options,download-options
|
18、SetPath GatewayFilter Factory
修改原始的请求路径,配置示例:
1 2 3 4 5 6 7 8 9 10 11
| spring: cloud: gateway: routes: - id: setpath_route uri: https://example.org predicates: - Path=/foo/{segment} filters: - SetPath=/{segment}
|
该配置使访问 ${GATEWAY_URL}/foo/bar
时会转发到 https://example.org/bar
,也就是原本的/foo/bar
被修改为了/bar
19、SetResponseHeader GatewayFilter Factory
修改原始响应中某个Header的值,配置示例:
1 2 3 4 5 6 7 8 9
| spring: cloud: gateway: routes: - id: setresponseheader_route uri: https://example.org filters: - SetResponseHeader=X-Response-Foo, Bar
|
将原始响应中 X-Response-Foo
的值修改为 Bar
20、SetStatus GatewayFilter Factory
修改原始响应的状态码,配置示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| spring: cloud: gateway: routes: - id: setstatusstring_route uri: https://example.org filters: - SetStatus=BAD_REQUEST - id: setstatusint_route uri: https://example.org filters: - SetStatus=401
|
SetStatusd的值可以是数字,也可以是字符串。但一定要是Spring HttpStatus
枚举类中的值。上面这两种配置都可以返回401这个HTTP状态码。
21、StripPrefix GatewayFilter Factory
用于截断原始请求的路径,配置示例:
1 2 3 4 5 6 7 8 9 10 11 12
| spring: cloud: gateway: routes: - id: nameRoot uri: http://nameservice predicates: - Path=/name/** filters: - StripPrefix=2
|
如上配置,如果请求的路径为 /name/bar/foo
,那么则会截断成/foo
后进行转发 ,也就是会截断2个路径。
22、Retry GatewayFilter Factory
针对不同的响应进行重试,例如可以针对HTTP状态码进行重试,配置示例:
1 2 3 4 5 6 7 8 9 10 11 12 13
| spring: cloud: gateway: routes: - id: retry_test uri: http://localhost:8080/flakey predicates: - Host=*.retry.com filters: - name: Retry args: retries: 3 statuses: BAD_GATEWAY
|
可配置如下参数:
retries
:重试次数statuses
:需要重试的状态码,取值在 org.springframework.http.HttpStatus
中methods
:需要重试的请求方法,取值在 org.springframework.http.HttpMethod
中series
:HTTP状态码序列,取值在 org.springframework.http.HttpStatus.Series
中
23、RequestSize GatewayFilter Factory
设置允许接收最大请求包的大小,配置示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| spring: cloud: gateway: routes: - id: request_size_route uri: http://localhost:8080/upload predicates: - Path=/upload filters: - name: RequestSize args: maxSize: 5000000
|
如果请求包大小超过设置的值,则会返回 413 Payload Too Large
以及一个errorMessage
24、Modify Request Body GatewayFilter Factory
在转发请求之前修改原始请求体内容,该过滤器工厂只能通过代码配置,不支持在配置文件中配置。代码示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| @Bean public RouteLocator routes(RouteLocatorBuilder builder) { return builder.routes() .route("rewrite_request_obj", r -> r.host("*.rewriterequestobj.org") .filters(f -> f.prefixPath("/httpbin") .modifyRequestBody(String.class, Hello.class, MediaType.APPLICATION_JSON_VALUE, (exchange, s) -> return Mono.just(new Hello(s.toUpperCase())))).uri(uri)) .build(); } static class Hello { String message; public Hello() { } public Hello(String message) { this.message = message; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } }
|
Tips:该过滤器工厂处于 BETA 状态,未来API可能会变化,生产环境请慎用
25、Modify Response Body GatewayFilter Factory
可用于修改原始响应体的内容,该过滤器工厂同样只能通过代码配置,不支持在配置文件中配置。代码示例:
1 2 3 4 5 6 7 8 9 10
| @Bean public RouteLocator routes(RouteLocatorBuilder builder) { return builder.routes() .route("rewrite_response_upper", r -> r.host("*.rewriteresponseupper.org") .filters(f -> f.prefixPath("/httpbin") .modifyResponseBody(String.class, String.class, (exchange, s) -> Mono.just(s.toUpperCase()))).uri(uri) .build(); }
|
Tips:该过滤器工厂处于 BETA 状态,未来API可能会变化,生产环境请慎用
26、Default Filters
Default Filters用于为所有路由添加过滤器工厂,也就是说通过Default Filter所配置的过滤器工厂会作用到所有的路由上。配置示例:
1 2 3 4 5 6
| spring: cloud: gateway: default-filters: - AddResponseHeader=X-Response-Default-Foo, Default-Bar - PrefixPath=/httpbin
|
官方文档:https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.1.0.RELEASE/single/spring-cloud-gateway.html#_gatewayfilter_factories
3.6.1局部过滤器
GatewayFilter 局部过滤器,是针对单个路由的过滤器。
在Spring Cloud Gateway 组件中提供了大量内置的局部过滤器,对请求和响应做过滤操作。
遵循约定大于配置的思想,只需要在配置文件配置局部过滤器名称,并为其指定对应的值,就可以让其生效
1 2 3 4 5 6 7 8 9
| - id: gateway-provider # 静态路由 # uri: http://localhost:8001/ # 动态路由 uri: lb://GATEWAY-PROVIDER predicates: - Path=/goods/** filters: - AddRequestParameter=username,zhangsan
|
3.6.2全局过滤器
自定义 全局过滤器
自定义 局部过滤器
GlobalFilter 全局过滤器,不需要在配置文件中配置,系统初始化时加载,并作用在每个路由上。
Spring Cloud Gateway 核心的功能也是通过内置的全局过滤器来完成。
自定义全局过滤器步骤:
1 2 3
| 1. 定义类实现 GlobalFilter 和 Ordered接口 2. 复写方法 3. 完成逻辑处理
|
MyFilter
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| package com.itheima.gateway.filter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain; import org.springframework.cloud.gateway.filter.GlobalFilter; import org.springframework.core.Ordered; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.http.server.reactive.ServerHttpResponse; import org.springframework.stereotype.Component; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Mono; import java.net.InetAddress; import java.net.InetSocketAddress; import static org.springframework.http.HttpStatus.FORBIDDEN;
@Component public class MyFilter implements GlobalFilter, Ordered { @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { System.out.println("自定义全局过滤器执行了~~~"); ServerHttpRequest request = exchange.getRequest(); ServerHttpResponse response = exchange.getResponse(); InetSocketAddress remoteAddress = request.getRemoteAddress(); String hostString = remoteAddress.getHostString(); System.out.println("hostString:"+hostString); String hostName = remoteAddress.getHostName(); System.out.println("hostName:"+hostName); InetAddress address = remoteAddress.getAddress(); System.out.println("address:"+address); if (hostString.contains("1.1.1.1")){ response.setStatusCode(FORBIDDEN); return response.setComplete(); } return chain.filter(exchange); }
@Override public int getOrder() { return 1; } }
|
ip过滤 淘宝ip 1.1.1.1
危险操作 记录日志
http 响应码
2** 访问成功 200
3** 访问成功,但是做额外操作 303 重定向
4** 客户端请求有问题 404
5** 服务端有问题 500 501 503
作业:
1使用log4l self4j logbak 分别在项目一中把 info error打出来
2隔离 线程池 信号量 默认参数 怎么改
3.7 使用log4l
log4j.properties配置文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| log4j.rootLogger = debug,stdout,D,E
log4j.appender.stdout = org.apache.log4j.ConsoleAppender log4j.appender.stdout.Target = System.out log4j.appender.stdout.layout = org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n
log4j.appender.D = org.apache.log4j.DailyRollingFileAppender log4j.appender.D.File = E://logs/log.log log4j.appender.D.Append = true log4j.appender.D.Threshold = DEBUG log4j.appender.D.layout = org.apache.log4j.PatternLayout log4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n
log4j.appender.E = org.apache.log4j.DailyRollingFileAppender log4j.appender.E.File =E://logs/error.log log4j.appender.E.Append = true log4j.appender.E.Threshold = ERROR log4j.appender.E.layout = org.apache.log4j.PatternLayout log4j.appender.E.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n
|
导入pom配置(log4j的依赖)
1 2 3 4 5 6 7 8 9 10 11 12 13
| <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.21</version> </dependency>
<dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.7.21</version> </dependency> </dependencies>
|
在类里使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| package com.itheima.gateway.filter; import org.apache.log4j.Logger; import org.springframework.cloud.gateway.filter.GatewayFilterChain; import org.springframework.cloud.gateway.filter.GlobalFilter; import org.springframework.core.Ordered; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.http.server.reactive.ServerHttpResponse; import org.springframework.stereotype.Component; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Mono;
import java.net.URI; @Component public class MyOperationFilter implements GlobalFilter, Ordered { private static Logger logger = Logger.getLogger(MyOperationFilter.class);
@Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { ServerHttpRequest request = exchange.getRequest(); ServerHttpResponse response = exchange.getResponse(); URI uri = request.getURI(); System.out.println("URI:"+uri); logger.info("URI:"+uri); System.out.println("Host:"+uri.getHost()); logger.info("Host:"+uri.getHost()); System.out.println("Path::"+uri.getPath()); logger.info("Path::"+uri.getPath()); if (uri.toString().contains("goods")){ System.err.println("警告 访问了Goods"); logger.warn("警告:"+uri.toString()+"来访问了"); }
return chain.filter(exchange); }
@Override public int getOrder() { return 2; } }
|
总结:
1feign
导包 @EnableFeignClients 定义feign接口 复制粘贴
辅助功能
超时时间
1 2 3
| ribbon: ConnectTimeout: 1000 # 连接超时时间 默认1s ReadTimeout: 3000 # 逻辑处理的超时时间 默认1s
|
日志记录
配置文件 配置类 feign客户端配置
2hystrix 熔断器 保险丝
隔离 线程池隔离 信号量隔离
降级
提供方 导包 主启动类 降级方法 HystrixCommand
调用方 配置文件开启 feign接口实现类 告诉feign(fallback = GoodsFeignFallbak.class)
熔断
限流 不用
3网关 gateway 路由+过滤
不用网关问题
网关架构图
路由:
配置文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| routes: #集合。 # id: 唯一标识。默认是一个UUID # uri: 转发路径 # predicates: 条件,用于请求网关路径的匹配规则 # filters:配置局部过滤器的 - id: gateway-provider # 静态路由 #uri: http://localhost:8000/ # 动态路由 uri: lb://EUREKA-PROVIDER predicates: - Path=/goods/** filters: - AddResponseHeader=a,b
|
过滤:
内置局部
1 2
| filters: - AddResponseHeader=a,b
|
内置全局
1 2
| default-filters: - AddResponseHeader=c,d
|
自定义局部 *
自定义全局 重点
实现两个接口 gloableFilters Ordered
ip过滤 淘宝ip 1.1.1.1
危险操作 记录日志