spring-cloud-gateway 入门使用
1. 基本介绍
网关开发中一般指的是: 应用的统一流量入口,负责转发请求到指定服务;
spring-cloud-gateway : 基于spring5.0, spring boot 2.0 , project reactor 等技术开发的网关,目的是为 微服务架构
提供一种简单有效的统一的API路由管理方式;
1.1 通用网关功能
以下是网关的基本功能结构,围绕这几个点开始学习;
1.2 特有属性介绍
SpringCloud 官网介绍:
-
基于spring framework 5 , project reactor 和spring boot 2.0 ;
-
集成Hystrix 断路器 ;
-
集成 spring cloud discoveryClient (可以整合 eurake、ribbon, 实现负载均衡) ;
-
predicate 和 filter 作用于特定路由,易于编写的 Predicates 和filters ;
-
具有一些网关的高级功能: 动态路由、限流、路径重写;
Predicate (断言)
java8的 predicate,可以用它来匹配 Http 请求的任何内容, 例如 headers 或参数, 断言的输入类型是一个 ServerWebExchange ;
Route (路由)
由一个跳转URI、一组predicate、一组Filter 组成的处理单元;
Filter(过滤器)
拦截和修改请求;
2. 入门使用
2.1 代码配置
以接口登录认证为例,我们实现一个简单的网关需求;
需求简单描述:
/login /send_code 等 这些不需要认证的接口 我们以配置的形式 体现;
其他接口,统一都需要认证;
注:header中含有user_token ,标识已登录
核心实现类:AuthGatewayFilterFactory
@Component
public class AuthGatewayFilterFactory extends AbstractGatewayFilterFactory<AuthGatewayFilterFactory.Config> {
private Logger logger = LoggerFactory.getLogger(AuthGatewayFilterFactory.class);
/**
* 用户登录状态token
*/
private static final String USER_TOKEN = "user_token";
public AuthGatewayFilterFactory(){
super(Config.class);
logger.info("AuthGatewayFilterFactory init");
}
@Override
public List<String> shortcutFieldOrder() {
return Collections.singletonList("ignoreUrlListStr");
}
@Override
public GatewayFilter apply(Config config) {
return (exchange, chain) -> {
ServerHttpRequest request = exchange.getRequest();
// 校验是否是 不用登录的URL
String path = request.getPath().toString();
logger.info("AuthGatewayFilterFactory.apply path:{}",path);
String ignoreUrlListStr = config.ignoreUrlListStr;
logger.info("AuthGatewayFilterFactory.apply ignoreUrlListStr={}",ignoreUrlListStr);
boolean ignoreOk = Arrays.asList(ignoreUrlListStr.split("\|")).contains(path);
if(ignoreOk){
return chain.filter(exchange);
}
// 校验是否登录
HttpHeaders headers = request.getHeaders();
String userToken = headers.getFirst(USER_TOKEN);
if(StringUtils.isEmpty(userToken)){
// 返回未登录提示
ServerHttpResponse response = exchange.getResponse();
response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
response.setStatusCode(HttpStatus.UNAUTHORIZED);
Map<String, Object> bodyMap = new HashMap<>();
bodyMap.put("code",-1000003);
bodyMap.put("message","未登录");
byte[] responseByteArray = JSON.toJSONBytes(bodyMap);
DataBuffer responseBuffer = response.bufferFactory().allocateBuffer(responseByteArray.length).write(responseByteArray);
return response.writeWith(Mono.just(responseBuffer));
}
logger.info("AuthGatewayFilterFactory.apply user-token={}",userToken);
return chain.filter(exchange);
};
}
public static class Config {
private String ignoreUrlListStr;
public String getIgnoreUrlListStr() {
return ignoreUrlListStr;
}
public void setIgnoreUrlListStr(String ignoreUrlListStr) {
this.ignoreUrlListStr = ignoreUrlListStr;
}
}
}
application.properties 配置
# 网关配置 -- 免登录认证配置
spring.cloud.gateway.routes[0].id = login_auth
spring.cloud.gateway.routes[0].uri = https://www.baidu.com
spring.cloud.gateway.routes[0].predicates[0] = Path=/**
spring.cloud.gateway.routes[0].filters[0] = Auth=/login|/send_code
以上配置解释如下: 定义一个路由: 名称:登录认证
跳转URL: 百度地址 断言: 拦截所有请求
过滤器: 除 /login ,/send_code 外 都进行拦截处理;
2.2 运行效果
非免检未登录
curl --location --request GET 'localhost:80/eat/apple'
{
"code": -1000003,
"message": "未登录"
}
非免检已登录
curl --location --request GET 'localhost:80/eat/apple' \
--header 'user_token: 12138'
NOT FOUND
免检接口
curl --location --request GET 'localhost:80/login'
Not Found
3. 整合apollo
3.1 准备环境
首先准备apollo 环境,参见 apollo-sh 这个项目;
3.2 项目配置
pom.xml
<properties>
<java.version>1.8</java.version>
<lombok.version>1.18.10</lombok.version>
<fastjson.version>1.2.78</fastjson.version>
<spring-cloud-version>2.1.0.RELEASE</spring-cloud-version>
<apollo-client.version>1.9.1</apollo-client.version>
</properties>
<dependency>
<groupId>com.ctrip.framework.apollo</groupId>
<artifactId>apollo-client</artifactId>
<version>${apollo-client.version}</version>
</dependency>
application.yml
# apollo 启动配置
app:
id: yiyi-gateway
apollo:
bootstrap:
namespaces: application
enabled: true
meta: http://172.16.146.231:9001
ENV: DEV
注:到这里,我们就可以把之前在application.yml 中的gateway 配置移动到 apollo中了;
解决apollo 更改配置项目不同步问题
/**
* apollo 刷新 gateway配置不同步 问题解决
*/
@Component
public class GatewayPropertiesRefresher implements ApplicationContextAware, ApplicationEventPublisherAware {
private static final Logger logger = LoggerFactory.getLogger(GatewayPropertiesRefresher.class);
private ApplicationContext applicationContext;
private ApplicationEventPublisher publisher;
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
this.publisher = applicationEventPublisher;
}
@ApolloConfigChangeListener
public void onChange(ConfigChangeEvent changeEvent) {
this.applicationContext.publishEvent(new EnvironmentChangeEvent(changeEvent.changedKeys()));
this.publisher.publishEvent(new RefreshRoutesEvent(this));
logger.info("GatewayPropertiesRefresher.onChange apollo GatewayProperties refreshed");
}
}
4. 整合eureka
<properties>
<java.version>1.8</java.version>
<lombok.version>1.18.10</lombok.version>
<fastjson.version>1.2.78</fastjson.version>
<spring-cloud-version>2.1.0.RELEASE</spring-cloud-version>
<apollo-client.version>1.9.1</apollo-client.version>
</properties>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
<version>${spring-cloud-version}</version>
</dependency>
5. 整合sentinel
5.1 准备环境
参见:github-sentinel 快速启动项目;
5.2 项目配置
pom.xml
<!--alibaba 流量卫士-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
<version>2.1.0.RELEASE</version>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
<version>2.1.0.RELEASE</version>
</dependency>
application.yml
spring:
cloud:
# sentinel 限流配置
sentinel:
transport:
dashboard: yiyi.cn:18085
port: 18085
# 服务启动直接建立心跳连接
eager: true
运行校验
注:参见sentinel 官方文档, 整一个测试脚本 run一下即可
参见
Spring-Cloud-Gateway 源码解析 —— 网关管理 HTTP API
转载自:https://juejin.cn/post/7047469654503063560