1. Spring cloud Gateway网关
- 什么是网关?
网关就是网络请求的统一入口。gateway是spring cloud的第二代网关,未来会取代zuul,其性能是zuul的1.6倍左右,其内部是基于netty、reactor、webflux进行构建的。gateway需要从注册中心获取服务,然后通过网关来调用对应的服务。注意gate不在web环境下运行,也就是说不能打成war包放在tomcat下运行。
- 为什么需要网关?
从服务器与后端两个维度来谈一下为什么需要网关:1.如果我们有成千上万个服务,我们在请求每个服务的时候都需要认证,难度可想而知;2.如果没有统一的入口,那么前端与服务端交互的时候定位到各个服务,假设服务端进行服务的重构(比如改变访问接口),那么前端也得跟着一起修改。
2. 应用环境
注意查看官网(https://spring.io/projects/spring-cloud-alibaba)最新适配环境
Spring Cloud Version | Spring Cloud Alibaba | Version Spring Boot Version |
---|---|---|
Spring Cloud Greenwich | 2.1.x.RELEASE | 2.1.x.RELEASE |
Spring Cloud Finchley | 2.0.x.RELEASE | 2.0.x.RELEASE |
Spring Cloud Edgware | 1.5.x.RELEASE | 1.5.x.RELEASE |
如上官方给出的最新适配版本为:
Spring Boot:2.1.0
Spring Cloud:Greenwich.SR2
Spring Cloud Alibab:2.1.0.RELEASE
注意:如果使用最新而没有适配的版本,可能会出现以下问题:无法通过API网关访问服务,Sentinel限流中链路失败
3. 上手使用
1. 添加依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<!-- 排除掉springmvc相关的配置信息 -->
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
</exclusion>
<!-- 排除掉tomcat相关的配置 -->
<exclusion>
<groupId>org.springframework.bootk</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-core</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-el</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-websocket</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- 网关相关配置 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
</dependencies>
2. yml文件配置
server:
port: 9090
spring:
application:
# 服务名
name: alibaba-gateway
cloud:
nacos:
discovery:
register-enabled: true
server-addr: 172.18.96.177:8848
gateway:
discovery:
locator:
# 可以使用服务名的方式访问,例如
# http://localhost:9090/alibaba-provider/user
enabled: true
3. 术语
- Route路由:gateway的基本构建模块。它由ID、目标URI、断言集合和过滤器集合组成。如果聚合断言结果为真,则匹配到该路由。
- Predicate断言:谓词(predicate)是gateway内置的的一下关于请求相关的处理
- Filter过滤器:GateWay提供了很多内置的过滤器让我们使用,具体的过滤器在spring-cloud-gateway-core-2.1.2.RELEASE.jar下的org.springframework.cloud.gateway.filter.factory包下。也可以自定义过滤器在返回请求之前或之后修改请求和响应的内容。
spring:
application:
# 服务名
name: alibaba-gateway
cloud:
gateway:
discovery:
locator:
# 可以使用服务名的方式访问,例如
# http://localhost:9090/alibaba-consumer/all/user?origin=abc
# http://localhost:9090/alibaba-provider/user
# true表示开始,false表示关闭
enabled: false
routes:
- id: alibaba-consumer
#如果要定位到微服务中的某个服务,要使用 lb:// 开头
uri: lb://alibaba-consumer
predicates:
# 路径匹配
- Path=/all/user,/student/**
# 表示请求的参数中必须包含origin而且参数的值必须是 数字字母或_组成的字符串
- Query=origin,\w+
# 请求方式必须为get请求
- Method=get
- After=2019-11-12T00:00:00+08:00[Asia/Shanghai]
- Before=2019-12-31T00:00:00+08:00[Asia/Shanghai]
# 请求头中必须包含token
#- Header=token,\w+
# 描述从172.18.96.1~172.18.96.255的ip地址才可以访问
- RemoteAddr=172.18.96.0/24
filters:
# (?) 表示将这一组数据抽取出来,<abc>将抽取的数据赋值给abc
# /ac/users/23 abc=/users/23 ${abc}
# http://localhost:9091/ac/users
- RewritePath=/ac(?<abc>/?.*),$\{abc}
- Customize=abc,XYZ
filters:
- name: RequestRateLimiter
args:
# key-resolver是用于限流的bean对象,通过SpEL的方式 #{@XXX} 取出spring容器中的bean
keyResolver: '#{@hostAddrKeyResolver}'
# 每秒往令牌桶中存放的数量
redis-rate-limiter.replenishRate: 1
# 令牌桶初始容量
redis-rate-limiter.burstCapacity: 3
redis:
host: localhost
port: 6379
password: admin
<font color="red">id:</font> 可以配置很多的路由信息,但是每个路由都有一个唯一的id来标识。
<font color="red">uri:</font> 转发的地址,lb://开头标识转发到微服务的内部的某个服务。
<font color="red">predicates:</font> 配置谓词。
<font color="red">Path:</font> 配置请求的路径
<font color="red">Query:</font> 请求的参数
<font color="red">Method:</font> 请求的方式,大小写不敏感
<font color="red">After:</font> 在指定的时间之后
<font color="red">Before:</font> 在指定的时间之前
<font color="red">Header:</font> 请求头中要包含的信息
<font color="red">RemoteAddr:</font> 请求的IP的来源
4. 过滤器
- 内置过滤器RewritePathGatewayFilterFactory
在Nginx服务启中有一个非常强大的功能就是重写路径,Spring Cloud Gateway默认也提供了这样的功能,这个功能是Zuul没有的。
gateway:
routes:
- id: rewritepath_route
uri: https://blog.csdn.net
predicates:
- Path=/foo/**
filters:
- RewritePath=/foo/(?<segment>.*), /$\{segment}
/**上面的配置表示所有的/foo/**开始的路径都会到转发
*到https://blog.csdn.net/forezp的页面
*/
- 自定义局部过滤器
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.factory.AbstractNameValueGatewayFilterFactory;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
/**
* spring5.X 版本之后加入 webflux模块, 该模块主要用于反应式编程。
* 如果要返回单个值(例如User), return Mono;
* 如果要返回列表:return Flux;
*/
@Component
public class CustomizeGatewayFilterFactory extends AbstractNameValueGatewayFilterFactory {
/**
* Customize=abc,XYZ
*/
@Override
public GatewayFilter apply(NameValueConfig config) {
// 针对如上的配置,config.getName() 为abc, config.getValue()为XYZ
// System.out.println(config.getName() + ":::" + config.getValue());
GatewayFilter gatewayFilter = new GatewayFilter() {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
String username = request.getQueryParams().get("username").get(0);
System.out.println(username);
//该代码的意思是向请求头中添加信息 auth abcdef
request.mutate().header("auth", "abcdef");
// mutate是修改的意思, 将修改之后的request加入新的请求中
ServerWebExchange serverWebExchange = exchange.mutate().request(request).build();
return chain.filter(serverWebExchange);
}
};
return gatewayFilter;
}
}
配置:
routes:
- id: alibaba-consumer
uri: lb://alibaba-consumer
predicates:
- Path=/ac/users
filters:
# (?) 表示将这一组数据抽取出来,<abc>将抽取的数据赋值给abc
# /ac/users/23 abc=/users/23 ${abc}
# http://localhost:9091/ac/users
- RewritePath=/ac/(?<abc>/?.*),$\{abc}
- Customize=abc,XYZ
- 自定义全局过滤器
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
/**
* 因为在网关内部过滤器的顺序都是整数,我们自己在定义过滤器的时候,采用负数,数字越小越先执行
*/
@Configuration
public class GatewayConfig {
@Bean
@Order(-1)
public GlobalFilter globalFilter() {
return new GlobalFilter() {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
System.out.println("全局过滤器1");
return chain.filter(exchange);
}
};
}
@Bean
@Order(-2)
public GlobalFilter secondGlobalFilter() {
return new GlobalFilter() {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
System.out.println("全局过滤器2");
return chain.filter(exchange);
}
};
}
}
网友评论