SpringCloud Gateway网关
05、Gateway:网关介绍
官网学习地址:https://spring.io/projects/spring-cloud-gateway#learn
Spring Cloud Gateway简介
- Gateway基于Spring 5.0+、Spring Boot 2.0+、WebFlux、Netty等技术开发的网关服务。
- Gateway基于Filter链提供网关基本功能:断言、路由、过滤、限流等。
- Gateway为微服务架构提供简单、有效、统一的API路由管理方式。
- Gateway是替代Netflix公司Zuul的一套解决方案。
Gateway组件的核心是一系列的过滤器,通过这些过滤器可以将客户端发送的请求转发(路由)到对应的微服务。 Spring Cloud Gateway是加在整个微服务最前面的防火墙和代理器,隐藏微服务节点IP与端口信息,从而达到保护微服务的目的。Spring Cloud Gateway本身也是一个微服务,且必须连接到Eureka服务注册中心,因为需要拉取服务列表,才能做转发请求。
Gateway加入后的架构
说明:不管是来自于客户端(PC或移动端)的请求,还是服务内部调用。一切对服务的请求都可经过网关,然后再由网关来实现鉴权、动态路由等等操作。Gateway就是我们微服务调用的统一入口。
核心概念:
-
路由(route):由一个ID、一个目标URI、一组断言工厂、一组过滤器组成。如果断言为真,该请求就会 路由到 目标URI。
-
断言(Predicate):用断言工厂去匹配请求URL。如果能匹配,断言为真。
-
过滤器(Filter):用过滤器过滤请求,例如过滤请求URL、过滤请求参数、过滤请求头等。
06、Gateway:快速入门
6.1 创建模块
- 填写基本信息
- 添加依赖
-
<?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>springcloud-demo</artifactId> <groupId>cn.itcast</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>gateway-server</artifactId> <dependencies> <!-- 配置eureka客户端启动器 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <!-- 配置gateway启动器(基于netty运行,所在不需要tomcat启动器) --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency> </dependencies> </project>
6.2 编写启动类
在gateway-server中创建cn.itcast.GatewayApplication启动类
package cn.itcast;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient
public class GatewayApplication {
public static void main(String[] args){
SpringApplication.run(GatewayApplication.class, args);
}
}
6.3 编写配置
在gateway-server中创建application.yml文件,内容如下:
server:
port: 10010
spring:
application:
name: api-gateway
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka,http://localhost:8762/eureka
注意:必须设置拉取服务为true(默认也是为true),因为需要转发请求到具体服务,或者使用默认值
6.4 编写路由规则
- 启动三个Spring Boot应用:
- 需要用网关来代理user-service服务,先看一下控制面板中的服务状态:
-
修改gateway-server的application.yml文件:
server: port: 10010 spring: application: name: api-gateway cloud: gateway: routes: # 路由id, 路由信息的唯一标识, 可以随意写 - id: user-service-route # 路由的目标服务地址 uri: http://127.0.0.1:9001 # 断言,Path: 匹配路由映射路径 predicates: - Path=/** eureka: client: service-url: defaultZone: http://localhost:8761/eureka,http://localhost:8762/eureka
- 将符合 Path 规则的一切请求,都代理或路由到 uri 参数指定的地址
- 本例中,我们将路径中包含有 /** 开头的请求,代理到http://127.0.0.1:9001
6.5 启动测试
访问的路径中需要加上配置规则的映射路径,我们访问:http://localhost:10010/user/1
07、Gateway:面向服务路由
在刚才的路由规则中,把路径对应的服务地址写死了!如果同一服务有多个实例的话,这样做显然不合理。 应该根据服务的id,去Eureka注册中心查找服务对应的所有实例列表,然后进行动态路由!
-
修改映射配置,通过服务名称获取
因为已经配置了Eureka客户端,可以从Eureka获取服务的地址信息。修改application.yml文件:
server: port: 10010 spring: application: name: api-gateway cloud: gateway: routes: # 路由id,可以随意写 - id: user-service-route # 代理的服务地址;lb表示负载均衡(从eureka中根据服务id获取服务实例) # loadBalance uri: lb://user-service # 断言,Path: 配置路由映射路径 predicates: - Path=/** eureka: client: service-url: defaultZone: http://localhost:8761/eureka,http://localhost:8762/eureka
路由配置中uri所用的协议为lb时(以uri: lb://user-service为例),gateway将使用 LoadBalancerClient把user-service通过eureka解析为实际的主机和端口,并进行ribbon负载均衡。
启动测试
再次启动,这次gateway进行代理时,会利用Ribbon进行负载均衡访问:
-
说明: spring-cloud-gateway网关服务,默认就已经集成了Ribbon负载均衡(轮询算法)
08、Gateway:路由前缀
8.1 添加前缀
在gateway中可以通过配置网关过滤器PrefixPath,实现映射路径中的地址添加前缀,修改application.yml文件:
server:
port: 10010
spring:
application:
name: api-gateway
cloud:
gateway:
routes:
# 路由id,可以随意写
- id: user-service-route
# 代理的服务地址;lb表示负载均衡(从eureka中根据服务id获取服务实例)
uri: lb://user-service
# 断言,配置路由映射路径
predicates:
- Path=/**
filters:
# 添加前缀: 指定路由路径需要添加的前缀
- PrefixPath=/user
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka,http://localhost:8762/eureka
通过 PrefixPath=/xxx 来指定了路由要添加的前缀。
-
PrefixPath=/user,转换效果: http://localhost:10010/1 => http://localhost:9001/user/1
-
PrefixPath=/user/abc,转换效果: http://localhost:10010/1 => http://localhost:9001/user/abc/1 以此类推。
8.2 去除前缀
在gateway中可以通过配置网关过滤器StripPrefix,实现映射路径中的地址去除前缀,修改application.yml文件:
server:
port: 10010
spring:
application:
name: api-gateway
cloud:
gateway:
routes:
# 路由id,可以随意写
- id: user-service-route
# 代理的服务地址;lb表示负载均衡(从eureka中根据服务id获取服务实例)
uri: lb://user-service
# 断言,Path: 配置路由映射路径
predicates:
- Path=/**
filters:
# 去除前缀: 1去除一个前缀,2去除两个前缀,以此类推
- StripPrefix=1
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka,http://localhost:8762/eureka
通过 StripPrefix=1 来指定了路由要去掉的前缀个数。如:路径 /api/user/1 将会被代理到 /user/1。
- StripPrefix=1,转换效果: http://localhost:10010/api/user/1 => http://localhost:9001/user/1
- StripPrefix=2,转换效果:http://localhost:10010/api/user/1 => http://localhost:9001/1
以此类推。
作用:通过路由前缀可区分微服务,且可以对用户隐藏服务真实url
09、Gateway:过滤器介绍
过滤器简介
Gateway作为网关的其中一个重要功能,就是实现请求的鉴权。而这个动作往往是通过网关提供的过滤器来实现的。前一章中的路由前缀 章节中的功能也是使用过滤器实现的。
-
Gateway自带过滤器有30多个,常见自带过滤器有:
过滤器名称 说明 AddRequestHeader 对匹配上的请求添加Header AddRequestParameters 对匹配上的请求添加参数 AddResponseHeader 对从网关返回的响应添加Header StripPrefix 对匹配上的请求路径去除前缀
-
详细的说明在: 官网链接
-
过滤器类型:
- 全局过滤器:自定义全局过滤器,需实现 GlobalFilter、Ordered两个接口。不需要在配置文件中配置,作用在所有的路由上。
- 局部过滤器:通过spring.cloud.routes.filters 配置在具体路由下,只作用在当前路由上,自带的30几个过滤器都可以配置。
过滤器执行生命周期
Spring Cloud Gateway 的 Filter 的生命周期有两个(前置过滤与后置过滤):“pre” 和 “post”,分别会在请求执行前调用 或 请求执行后调用。
过滤器使用场景(例举):
- 请求鉴权:判断用户是否登录,是否对某接口有权限等(前置过滤)
- 服务调用时长统计:在请求执行前记录时间,在请求执行后计算该服务的调用时间(后置过滤)。
10、Gateway:配置默认过滤器
我们可以将Spring Cloud Gateway自带的过滤器配置成默认过滤器: 不是针对一个路由;而是对全部路由有效。(相当于全局过滤器)
server:
port: 10010
spring:
application:
name: api-gateway
cloud:
gateway:
# 默认过滤器,对全部路由有效
default-filters:
# 添加响应头过滤器,添中一个响应头为name,值为admin
- AddResponseHeader=name,admin
routes:
# 路由id,可以随意写
- id: user-service-route
# 代理的服务地址;lb表示负载均衡(从eureka中根据服务id获取服务实例)
uri: lb://user-service
# 断言,Path: 配置路由映射路径
predicates:
- Path=/api/user/**
filters:
# 去除前缀: 1去除一个前缀,2去除两个前缀,以此类推
- StripPrefix=1
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka,http://localhost:8762/eureka
运行测试:
11、Gateway:自定义全局过滤器
需求:模拟一个登录的校验。基本逻辑:如果请求中有token参数,则认为请求有效,放行。
-
在gateway-server模块中编写全局过滤器: MyGlobalFilter
package cn.itcast.filter; import org.apache.commons.lang.StringUtils; import org.springframework.cloud.gateway.filter.GatewayFilterChain; import org.springframework.cloud.gateway.filter.GlobalFilter; import org.springframework.core.Ordered; import org.springframework.http.HttpStatus; import org.springframework.stereotype.Component; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Mono; /** 自定义全局过滤器 */ @Component public class MyGlobalFilter implements GlobalFilter, Ordered { @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { System.out.println("==全局过滤器MyGlobalFilter=="); String token = exchange.getRequest().getQueryParams().getFirst("token"); if (StringUtils.isBlank(token)){ // 设置响应状态码: 401 未授权 exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED); // 返回响应完成 return exchange.getResponse().setComplete(); } // 放行,让其它的过滤器继续执行 return chain.filter(exchange); } @Override public int getOrder() { // 值越小越先执行 return 1; } }
-
测试访问
-
访问 http://localhost:10010/api/user/1,页面提示401
-
访问 http://localhost:10010/api/user/1?token=abc
-
12、Gateway:集成Hystrix
目标: spring-cloud-gateway集成Hystrix实现线程隔离。
-
第一步:在gateway-server中,添加hystrix启动器
<!-- 配置hystrix启动器 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> </dependency>
-
第二步:配置线程隔离时间
# 线程隔离 hystrix: command: default: execution: isolation: thread: timeoutInMilliseconds: 1000
-
第三步:在默认过滤器中配置Hystrix过滤器(对全部路由有效)
spring: cloud: gateway: # 配置默认过滤器(对全部路由有效) default-filters: # 添加响应头,响应头的名称为name 值为admin - AddResponseHeader=name,admin - name: Hystrix # 配置Hystrix过滤器 args: # 配置两个参数 name: fallbackcmd fallbackUri: forward:/fallback
-
第四步:创建FallbackController.java控制器,提供服务降级方法
package cn.itcast.controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class FallbackController { @GetMapping("/fallback") public String fallback(){ return "您好,服务器正忙,请稍候再试。。。"; } }
-
第五步:测试
13、Gateway:高可用
-
启动多个Gateway服务,自动注册到Eureka,就可以形成集群。
-
Gateway被内部微服务访问,自动负载均衡(Ribbon)。
-
Gateway被外部访问,如PC端、移动端等。它们无法通过Ribbon进行负载均衡,那么该怎么办?
此时,可以使用其它的服务网关,来对Gateway做负载均衡。比如:【Nginx、Apache、F5】
-
-
Gateway与Feign的区别
- Gateway 作为整个应用的入口,接收所有的请求,如PC、移动端等,并且将不同的请求路由至不同的微服务,大部分情况下用作权限鉴定、流量控制。
- Feign 主要用于微服务与微服务之间的调用。
Memorial Day is 514 days |