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/ 在此对作者表示感谢 ...
随机推荐
- memcached 测试代码
转载请注明来源:https://www.cnblogs.com/hookjc/ #include<stdio.h> #include <iostream> #include & ...
- WordPress子模板继承
很多时候我们不想重写模板,而是想在某个模板的基础上进行修改,那么这个时候我们就需要用到模板继承技巧. 子主题开发 style.css 是必须的文件,只需要新增 Template: 父模板的文件夹名
- CentOS下搭建自动化测试基础框架:Jenkins+Maven+TestNG+ReportNG
1. 安装JDK 1.1 卸载系统默认已安装的open-jdk rpm -qa|grep java 查出来openjdk相关的应用,把查出来的所有都要通过下面的命令给卸载掉 rpm -e --node ...
- HashMap 的 7 种遍历方式与性能分析
前言 随着 JDK 1.8 Streams API 的发布,使得 HashMap 拥有了更多的遍历的方式,但应该选择那种遍历方式?反而成了一个问题. 本文先从 HashMap 的遍历方法讲起,然后再从 ...
- 关于es update异常 ScriptException[dynamic scripting for [groovy] disabled]
你需要在elasticsearch.yml中配置 script.disable_dynamic: false 然后别忘了重启.
- Solution -「CF 1060F」Shrinking Tree
\(\mathcal{Description}\) Link. 给定一棵 \(n\) 个点的树,反复随机选取一条边,合并其两端两点,新点编号在两端两点等概率选取.问每个点留到最后的概率. ...
- 这个杀手不太冷-kill家族
文章目录 kill killall pkill 跑路小技巧 kill家族: kill: # 删除执行中的程序或工作 killall: # 使用进程的名称来杀死进程,使用此指令可以杀死一组同名进程 pk ...
- MyBatis缓存Cache包
Mybatis默认使用了一级缓存为数据查询提供效率,其底层数据结构为PerpetualCache.同时MyBatis不止实现了PerpetualCache,还有其他实现提供其他功能,如下: 可以从UM ...
- MyBatis功能点二:MyBatis提供的拦截器平台
前面关于MyBatis功能点二plugin已经介绍了一些应用及其实现的底层代码,本文总结MyBatis提供的拦截器平台框架体系. 通过MyBatis功能点二:从责任链设计模式的角度理解插件实现技术 - ...
- Eureka工作原理及心跳机制
Eureka原理 1.基本原理上图是来自eureka的官方架构图,这是基于集群配置的eureka:处于不同节点的eureka通过Replicate进行数据同步Application Service为服 ...