GateWay配置使用
是什么
- Cloud全家桶中有个很重要的组建就是网关,在1.x版本中都是采用的Zuul网关
- 但在2.X版本中,zuul的升级一直跳票,SpringCloud最后自己研发了一个网关替代Zuul
- SpringCloudGateway:gateway是原zuul1.X版的替代.

- Gateway是在Spring生态系统之上构建的APL网关服务,基于Spring5、Spring Boot2和Project Reactor等技术
- Gateway指在提供一种简单的有效的方式来对API进行路由,以及提供一些强大的过滤器功能,例如:熔断、限流、重试等

SpringCloud Gateway是SpringCloud的一个全新项目,基于Spring 5.0+SpringBoot 2.0 和 ProjectReactor等技术开发的网关,它指在为微服务架构提供一种简单有效的统一的API路由管理方式
SpringCloud Gateway作为SpringCloud生态系统中的网关,目标是替代Zuul,在SpringCloud 2.0以上版本中,没有对新版本的Zuul 2.0以上最新高性能版本进行集成,仍然还是使用的Zuul 1.X非Reactor模式的老版本。而为了提升网关的性能,SpringCloud Gateway是基于WebFlux框架实现的,而WebFlux框架底层则使用了高性能的Reactor模式通信框架Netty
SpringCloud Gateway的目标提供统一的路由方式且基于Filter链的方式提供了网关基本的功能,例如:安全、监控/指标、和限流
SpringCloud Gateway使用的是WebFlux中的reactor-netty响应式编程组建,底层使用了Netty通讯框架
作用
- 反向代理
- 鉴权
- 流量控制
- 熔断
- 日志监控
位置

Gateway与Zuul的区别
在SpringCloud Finchley正式版之前,SpringCloud 推荐的网关是Netflix提供的Zuul
- Zuul 1.X,是一个基于阻塞I/O的API
- Zuul 1.X基于Servlet2.5使用阻塞架构它不支持任何长链接(如:WebSocket)Zuul的设计模式和Nginx较像,每次I/O操作都是从工作线程中选择一个执行,请求线程被阻塞到工作线程完成,但是差别是Nginx用C++实现,Zuul用Java实现,而JVM本身会有第一次加载较慢的情况,使的Zuul的性能相对较差
- Zuul 2.X理念更先进,想基于Netty非阻塞和支持长连接,但SpringCloud目前还没有整合。Zuul 2.X的性能较Zuul 1.X有较大的提升,在性能方面,根据官方提供的基准测试,SpringCloud Gateway的RPS(每秒请求数)是Zuul的1.6倍
- SpringCloud Gateway 建立在Spring Framework 5 、ProjectReactor和SpringBoot 2之上,使用非阻塞API
- SpringCloud Gateway还支持WebSocket,而且与Spring紧密集成拥有更好的开发体验
三大核心概念
Route(路由)
- 路由是构建网关的基本模块,它由ID,目标URI,一系列的断言和过滤器组成,如断言为true则匹配该路由
Predicate(断言)
- 参考的是Java8的java.util.function.Predicate
- 开发人员可以匹配HTTP请求中的所有内容(例如请求头或请求参数),如果请求与断言相匹配则进行路由
Filter(过滤)
- 指的是Spring框架中GatewayFilter的实例,使用过滤器,可以在请求被路由前或者之后对请求进行修改
理论总结

- web请求,通过一些匹配条件,定位到真正的服务节点,并在这个转发过程的前后,进行一些精细化控制
- predicate就是我们的匹配条件,而Filter,就可以理解为一个无所不能的拦截器,有了这两个元素,再加上目标url,就可以实现一个具体的路由了
Gateway工作流程

- 客户端向 Spring Cloud Gateway发出请求。然后在 Gateway Handler Mapping中找到与请求相匹配的路由,将其发送到 Gateway Web Handler.
- Handler再通过指定的过滤器链来将请求发送到我们实际的服务执行业务逻辑,然后返回
- 过滤器之间用虚线分开是因为过滤器可能会在发送代理请求之前或之后执行业务逻辑
- Filter在"pre"类型的过滤器可以做参数校验、权限校验、流量监控、日志输出、协议转换等
- 在"post"类型的过滤器中可以做响应内容、响应头的修改,日志的输出,流量监控等有着非常重要的作用
项目搭建
导包
注:gateway无需导入web包
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
<version>2.2.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
<version>2.2.5.RELEASE</version>
</dependency>
注册到Eureka
@SpringBootApplication
@EnableEurekaClient
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class, args);
}
}
指定某一台服务跳转
修改YML文件
server:
port: 8888
spring:
application:
name: gateway
cloud:
gateway:
routes:
- id: route1 # 路由的id,保证唯一,推荐以业务、微服务起名
uri: http://192.168.1.2 #匹配后提供服务的路由地址 访问192.168.1.2:8888实际执行的是192.168.1.2
predicates:
Path=/gateway/** # 路径匹配
- id: route2
uri: http://192.168.1.2
predicates:
Path=/route2/**
eureka: #注册中心配置
instance:
instance-id: gateway
prefer-ip-address: true
client:
fetch-registry: true
register-with-eureka: true
service-url:
defaultZone: http://192.168.1.2:8761/eureka/
测试
在client项目中创建一个方法feignGetInstance,路径为/gateway/feignGetInstance
启动gateway及之前搭建好的eureka\service\client项目(每个项目启动一个还是多个无所谓,本次主要测试gateway转发)
访问http://192.168.1.2:8888/gateway/feignGetInstance(gateway项目) 就相当于请求http://192.168.1.2/gateway/feignGetInstance(client项目)
指定服务名称跳转
上面配置的uri是某一台服务的地址,但如果是集群,需要配置Eureka中的服务名称
修改YML
新增如下配置
discovery:
locator:
enabled: true # 开启从注册中心动态创建路由的功能,利用微服务名称进行路由
修改如下配置
uri: lb://CLIENT-PROJECT
server:
port: 8888
spring:
application:
name: gateway
cloud:
gateway:
discovery:
locator:
enabled: true # 开启从注册中心动态创建路由的功能,利用微服务名称进行路由
routes:
- id: route1 # 路由的id,保证唯一,推荐以业务、微服务起名
uri: lb://CLIENT-PROJECT #匹配后提供服务的服务名称,从Eureka中Application一列就是
predicates:
Path=/gateway/** # 路径匹配
- id: route2
uri: http://192.168.1.2
predicates:
Path=/route2/**
eureka: #注册中心配置
instance:
instance-id: gateway
prefer-ip-address: true
client:
fetch-registry: true
register-with-eureka: true
service-url:
defaultZone: http://192.168.1.2:8761/eureka/
测试
启动多个client项目
访问http://192.168.1.2:8888/gateway/feignGetInstance会自动通过Application服务名通过LB负载均衡找到对应的某服务
通过JAVA代码配置路由规则
添加如下Bean
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
return builder.routes()
.route(r -> r.path("/getInstanceIdByTimeOut/*")
.uri("lb://SERVICE-PROJECT") //也可使用http://192.168.1.2....
.id("java_route")
)
.build();
}
测试
访问http://192.168.1.2:8888/getInstanceIdByTimeOut/1可发现也成功跳转
注意
path配置的路径要有对应的方法
过滤规则配置
routes:
- id: route1 # 路由的id,保证唯一,推荐以业务、微服务起名
uri: lb://CLIENT-PROJECT #匹配后提供服务的路由地址 访问192.168.1.2:8888实际执行的是192.168.1.2
predicates: #各种过滤条件
- Path=/gateway/** # 路径匹配
#- After=2020-11-13T16:35:15.064+08:00[Asia/Shanghai] #在指定时间之后才可以访问
#- Before=2021-11-13T16:38:15.064+08:00[Asia/Shanghai] #在指定时间之前才可以访问
#- Cookie=mycookie,test #有指定的cookie并且与val一致才可以访问
#- Header=X-Request-Id, 123 #请求头要有X-Request-Id属性,并且值为123才可以访问
#- Host=*.xxx.com #必须是某些域名才可以访问
#- Method=GET #必须是GET才能访问
#- Query=param, 123 # 要有参数名param并且值是123才能访问
filters:
#- AddRequestHeader=myHeader, hval #接口方可通过request.getHeader()获得这个值
#- AddRequestParameter=myParameter, pval #接口方可通过request.getParameter()获得这个值
自定义过滤器
可以拦截符合路由条件的所有请求,从而进行权限、拦截、限流等等操作,添加如下配置即可
package com.project.gateway.filter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.reactivestreams.Publisher;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.cloud.gateway.filter.NettyWriteResponseFilter;
import org.springframework.cloud.gateway.filter.factory.rewrite.CachedBodyOutputMessage;
import org.springframework.cloud.gateway.support.BodyInserterContext;
import org.springframework.cloud.gateway.support.DefaultClientResponse;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.http.*;
import org.springframework.http.client.reactive.ClientHttpResponse;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponseDecorator;
import org.springframework.stereotype.Component;
import org.springframework.util.MultiValueMap;
import org.springframework.web.reactive.function.BodyInserter;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.client.ExchangeStrategies;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.nio.CharBuffer;
import java.nio.charset.StandardCharsets;
import java.util.List;
@Component
@Slf4j
public class GateWayFilter implements GlobalFilter, Ordered {
@Override
public int getOrder() {
// 控制在NettyWriteResponseFilter后执行
return NettyWriteResponseFilter.WRITE_RESPONSE_FILTER_ORDER - 1;
}
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
return processResponse(exchange, chain);
}
private Mono<Void> processResponse(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();//获得入参\cookies\headers....
//List<String> headersval = request.getHeaders().get("headersval");
String param = request.getQueryParams().getFirst("param");
if (!StringUtils.isEmpty(param)) {
//可在这进行校验是否登录、权限等等
if(true) {
//权限如果不符合等等逻辑,进入
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse().setComplete();
}else{
//权限、限流等条件正常进入
//获得响应值start
ServerHttpResponseDecorator responseDecorator = new ServerHttpResponseDecorator(exchange.getResponse()) {
@Override
public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
HttpHeaders httpHeaders = new HttpHeaders();
//httpHeaders.add(HttpHeaders.CONTENT_TYPE, 设置一些值);
ResponseAdapter responseAdapter = new ResponseAdapter(body, httpHeaders);
DefaultClientResponse clientResponse = new DefaultClientResponse(responseAdapter, ExchangeStrategies.withDefaults());
Mono<String> rawBody = clientResponse.bodyToMono(String.class).map(s -> s);
BodyInserter<Mono<String>, ReactiveHttpOutputMessage> bodyInserter = BodyInserters.fromPublisher(rawBody, String.class);
CachedBodyOutputMessage outputMessage = new CachedBodyOutputMessage(exchange, exchange.getResponse().getHeaders());
return bodyInserter.insert(outputMessage, new BodyInserterContext())
.then(Mono.defer(() -> {
Flux<DataBuffer> messageBody = outputMessage.getBody();
Flux<DataBuffer> flux = messageBody.map(buffer -> {
CharBuffer charBuffer = StandardCharsets.UTF_8.decode(buffer.asByteBuffer());
DataBufferUtils.release(buffer);
// 将响应信息转化为字符串
String responseStr = charBuffer.toString();
responseStr="可编辑响应值";
return getDelegate().bufferFactory().wrap(responseStr.getBytes(StandardCharsets.UTF_8));
});
HttpHeaders headers = getDelegate().getHeaders();
// 修改响应包的大小,不修改会因为包大小不同被浏览器丢掉
flux = flux.doOnNext(data -> headers.setContentLength(data.readableByteCount()));
return getDelegate().writeWith(flux);
}));
}
};
//获得响应值end
return chain.filter(exchange.mutate().response(responseDecorator).build());
}
}
return chain.filter(exchange);
}
private class ResponseAdapter implements ClientHttpResponse {
private final Flux<DataBuffer> flux;
private final HttpHeaders headers;
@SuppressWarnings("unchecked")
private ResponseAdapter(Publisher<? extends DataBuffer> body, HttpHeaders headers) {
this.headers = headers;
if (body instanceof Flux) {
flux = (Flux) body;
} else {
flux = ((Mono) body).flux();
}
}
@Override
public Flux<DataBuffer> getBody() {
return flux;
}
@Override
public HttpHeaders getHeaders() {
return headers;
}
@Override
public HttpStatus getStatusCode() {
return null;
}
@Override
public int getRawStatusCode() {
return 0;
}
@Override
public MultiValueMap<String, ResponseCookie> getCookies() {
return null;
}
}
}
GateWay配置使用的更多相关文章
- Spring Gateway配置使用(一)
参考文档:Spring Gateway官方文档 , 玹霖的博客 1.Spring Gateway简介 Spring Cloud Gateway是Spring官方基于Spring 5.0,Spring ...
- zabbix java gateway配置实战案例
zabbix java gateway配置实战案例 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.部署tomcat服务 博主推荐阅读: CentOS: https://www. ...
- 【SpringCloud】Gateway 配置全局过滤器获取请求参数和响应值
[SpringCloud]Gateway 配置全局过滤器获取请求参数和响应值 实现Ordered接口getOrder()方法,数值越小越靠前执行,记得这一点就OK了. 获取请求参数RequestBod ...
- 使用Gateway配置路由以及动态路由
1. 新建module cloud-gateway-gateway9527 2. pom.xml <!--注意不需要web模块依赖,否则报错--> <?xml version=&qu ...
- Springcloud之gateway配置及swagger集成
前言 关于引入gateway的好处我网上找了下: 性能:API高可用,负载均衡,容错机制. 安全:权限身份认证.脱敏,流量清洗,后端签名(保证全链路可信调用),黑名单(非法调用的限制). 日志:日志记 ...
- Layer 创建 和 lamdba function 创建 和 API GateWay 配置 和 添加依赖
进入控制台 选择 Lamdba 服务 进入控制面板, 单击右边: 创建函数 然后进入此图界面 添加lamdba 函数 名称 选择运行环境:python 选择角色 选择现有角色, 角色创建 可以参考 无 ...
- gateway 配置
server: port: spring: application: name: api-gateway eureka: client: service-url: defaultZone: http: ...
- 学习一下 SpringCloud (六)-- 注册中心与配置中心 Nacos、网关 Gateway
(1) 相关博文地址: 学习一下 SpringCloud (一)-- 从单体架构到微服务架构.代码拆分(maven 聚合): https://www.cnblogs.com/l-y-h/p/14105 ...
- [译]How to Setup Sync Gateway on Ubuntu如何在ubuntu上安装sync-gateway
参考文章https://hidekiitakura.com/2015/03/21/how-to-setup-sync-gateway-on-ubuntudigitalocean/ 在此对作者表示感谢 ...
随机推荐
- Azure MFA 守护你的账户安全
一,引言 MFA 又名 "多因素身份认证",指用户在登录的时候提示输入其他形式的标识.如果只使用密码对用户进行身份验证,是特别不安全的,尤其是在密码泄露的情况下.为了提高安全性,启 ...
- Android文件的权限概念
//通过context对象获取一个私有目录的文件读取流 /data/data/packagename/files/userinfoi.txt FileInputStream fileInputS ...
- Function.prototype.bind、call与apply
学习Function.prototype.bind.call与apply时,看到一篇博客,学到一些内容,但由于博客时间太久,根据官方文档对内容进行一些修正:下文为修正过内容 前言 前段时间面试遇见一题 ...
- iOS团队代码规范
iOS团队代码规范 工程之始可能需要的工具: 1.使用CocoaPods类库管理工具.CocoaPods安装和使用教程. 2.下载安装注释插件VVDocumenter-Xcode. 一.项目结构管理 ...
- html页面动效
找到了一个喜欢的黑客帝国动效"https://files.cnblogs.com/files/blogs/718959/codeMatrix-master.zip?t=1643081202& ...
- 《Effective Python》笔记——第1章 用Pythonic方式来思考
一. 遵循PEP8风格指南. PEP8是对python代码格式而编订的风格指南.地址:https://www.python.org/dev/peps/pep-0008/ 个人觉得不一定完全按照PEP8 ...
- 一站式超全JavaScript数组方法大全
一站式JavaScript数组方法大全(建议收藏) 方法一览表 详细操作 本人总结了JavaScript中有关数组的几乎所有方法(包含ES6之后新增的),并逐一用代码进行演示使用,希望可以帮助大家! ...
- Pandas之groupby分组
释义 groupby用来分组,调用groupby 之后返回pandas.core.groupby.generic.DataFrameGroupBy,其实就是由一个个格式为(key, 分组后的dataf ...
- 从零开始实现一个分布式RPC框架
该rpc框架是一个mini版的dubbo.学习rpc之前,建议先了解NIO,Netty和Dubbo等知识.请移步网络编程 前言:(借用阿里大佬的一段话) 为什么要自己写一个RPC框架,我觉得从个人成长 ...
- 最好的Java开发工具---IDEA
IntelliJ IDEA工具的使用 1. 常见的Java集成开发工具 Eclipse IBM团队研发的一个开源的非常好用的集成开发环境.寓意:吞并Sun公司.不过Sun最终被Oracle公司收购了. ...