网关
网关是一个服务,是访问内部系统的唯一入口,提供内部服务的路由中转,额外还可以在此基础上提供如身份验证、监控、负载均衡、限流、降级与应用检测等功能。
业务作用
网关是业务服务,可以作为业务整体业务入口。微服务即是一个整体,也是个体。个体体现在所有的服务都是独立单一的,可以自行运行。整体表现在需要所有微服务都正常就能提供一个完整的服务,整体服务又依赖于注册中心,对外提供服务又依赖网关。外部进入的请求必须是安全有效,这样网关就需要检查安全性,有效性又需要进行限流。
功能
官网有提供详情文档gateway。
基本实现
依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
配置
spring:
cloud:
gateway:
routes:
- id: xxooroute
uri: http://localhost:8080
predicates:
- Path= /user/**
断言 predicates
主要使用中会用到这五种,官网还有很多可以去了解。
1、Query 请求必须包含的参数
2、Method 请求方式
3、Host 指定host请求
4、Cookie 指定cookie请求
5、Path 路径
配置文件方式
#路由设置
spring:
cloud:
gateway:
routes:
- id: userTest
uri: lb://user
predicates:
- Path= /user/**
- Query=testName
- Method=post
- Host=demoUser.com
- Cookie=name,token
整合Eureka
使用Eureka之后就可以直接用的服务名访问。
网关地址/服务名/地址
依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
spring:
cloud:
gateway:
discovery:
locator:
// 开启从eureka 拉取服务列表 并自动映射
enabled: true
//服务名小写
lower-case-service-id: true
eureka:
client:
service-url:
defaultZone: http://localhost:7001/eureka/
负载均衡
这个可以自定义开发,我这里直接使用默认就好了。
配置负载名字://服务
默认是lb负载
#路由设置
spring:
cloud:
gateway:
routes:
- id: userTest
uri: lb://user
自定义过滤器
这个才是业务经常使用功能。
过滤器类
package com.spring.sample.router.filter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.util.MultiValueMap;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import java.util.List;
/**
* 拦截器定义
*
* 拦截器生效还需要添加到GlobalFilter bean容器
* @Bean
* public GlobalFilter customFilter() {
* return new UserTestFilter();
* }
*
* 拦截器可以鉴权
* 日志
* 链路追踪
*
*
*/
@Component
public class UserTestFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest serverHttpRequest = exchange.getRequest();
MultiValueMap<String, String> queryParams = serverHttpRequest.getQueryParams();
List<String> list = queryParams.get("testName");
if (null == list || list.size() ==0) {
// 非法请求
System.out.println("拦截");
// exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
// return exchange.getResponse().setComplete();
DataBuffer dataBuffer = exchange.getResponse().bufferFactory().wrap("没有testName".getBytes());
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse().writeWith(Mono.just(dataBuffer));
}
return chain.filter(exchange);
}
//优选级 越大越后执行
@Override
public int getOrder() {
return 0;
}
}
添加bean
@Bean
public GlobalFilter customFilter() {
return new UserTestFilter();
}
权重
该Weight路线谓词工厂有两个参数:group和weight(一个int)。权重是按组计算的。就是配置组中每个路由触发执行的概率。
routes:
- id: w1
predicates:
- Path=/w/**
- Weight=service,95
uri: lb://MDB
- id: w2
predicates:
- Path=/w/**
- Weight=service,5
uri: lb://MDB2
限流
内置令牌桶 + Redis
redis 依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>
启动一个标准版的redis就可以,不过也配置redis 的信息。
配置限流信息
filters:
- StripPrefix=1
- name: RequestRateLimiter
args:
# 限流条件
key-resolver: '#{@userKeyResolver}'
#每秒执行请求 不任何丢弃的请求
redis-rate-limiter.replenishRate: 10
#一秒内执行的最大请求数 这是令牌桶可以容纳的令牌数量。将此值设置为零会阻止所有请求。
redis-rate-limiter.burstCapacity: 20
添加限流条件bean
/**
* 限流参数条件
* @return
*/
@Bean
KeyResolver userKeyResolver() {
return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("testName"));
}
完整配置
#gateway 官网推荐使用 yaml 避免使用差别就使用yaml文件配置
server:
port: 80
#路由设置
spring:
application:
name: gateway
cloud:
gateway:
routes:
#路由Id 标识
- id: userTest
#路由URL
# 1、直接指定服务地址 http://localhost:8080
# 2、lb://user 负债均衡 + 服务名 需要使用注册中心
# 3、user 服务名 需要使用注册中心
uri: lb://user
# 断言 predicates
#1、Query 请求必须包含的参数
#2、Method 请求方式
#3、Host 指定host请求
#4、Cookie 指定cookie请求
#5、Path 路径
predicates:
- Path= /user/**
# 权重 相同分组(groupUser)请求过来的比例 (5),权重总共一百
- Weight=groupUser,5
# - Query=testName
# - Method=post
# - Host=demoUser.com
# - Cookie=name,token
# filters 过滤几级路径
filters:
- StripPrefix=1
- id: userTestV2
uri: lb://user
predicates:
- Path= /user/test1/**
- Weight=groupUser,95
filters:
- StripPrefix=1
- name: RequestRateLimiter
args:
# 限流条件
key-resolver: '#{@userKeyResolver}'
#每秒执行请求 不任何丢弃的请求
redis-rate-limiter.replenishRate: 10
#一秒内执行的最大请求数 这是令牌桶可以容纳的令牌数量。将此值设置为零会阻止所有请求。
redis-rate-limiter.burstCapacity: 20
# discovery:
# locator:
# # 开启从eureka 拉取服务列表 并自动映射
# enabled: true
# #服务名小写
# lower-case-service-id: true
eureka:
client:
service-url:
defaultZone: http://localhost:7001/eureka/
management:
endpoints:
web:
exposure:
include: '*'
代码地址
https://gitee.com/zhang798/spring-cloud/tree/gateway
分支:gateway
git clone https://gitee.com/zhang798/spring-cloud.git -b gateway