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/ 在此对作者表示感谢 ...
随机推荐
- Java BigDecimal 的舍入模式(RoundingMode)详解
BigDecimal.divide方法中必须设置roundingMode,不然会报错. ROUND_UP:向正无穷方向对齐(转换为正无穷方向最接近的所需数值) ROUND_DOWN:向负无穷方向对齐 ...
- Nginx 路由转发配置(转)
Nginx 路由转发配置笔记 由于预算有限,只有一台服务器,想要玩的东西不少,所以这个台服务器上会提供多重服务,因此涉及到的nginx转发就必有重要了 由nginx做请求代理,提供多种服务 php搭建 ...
- React凤凰项目规范
技术资源 基础语法 ES6 TS 框架 React Redux React-redux React-Router UmiJS Dva 组件库 AntDesign AntV 构建编译 Webpack b ...
- PHP中的单引号跟双引号的区别
不同点: 单引号只能解析转义字符"'"和"\",其他的原样输出.
- Linux-一次执行多个命令 ; && ||
一次执行多个命令,多个命令之间用:号隔开 cmd1;cmd2:cmd3 这样前后执行的时候没有依赖性,如果有下列要求呢 1. cmd1执行失败那就不要执行后面的命令 2. cmd1失败了才去指令后面的 ...
- 关于String不可变的一些理解
原创:转载需注明原创地址 https://www.cnblogs.com/fanerwei222/p/11683720.html 一直对String不可变感到疑问, 不知为何说String是不可变的, ...
- Sublime Python3编译环境修改
http://blog.csdn.net/qq_33304418/article/details/63337602 添加编译环境python3.6 Tools -> Build Syst ...
- soc AXI接口术语和特性
AXI接口术语和特性 1.outstanding 2.interleaving 3.out-of-oder 4.写数据可以优先于写地址 5.大小端 小端:低地址数据放在总线bus的低位. 大端:低地址 ...
- 关于WebStorm-React-Native 代码提示安装方法
声明 本方法 为网上好心人提供 我提供整理 插件名称:Webstrom live template 安装方法一:1.打开终端输入 git clone https://github.com/virto ...
- tomcat 配置https证书 ssl
修改tomcat-conf-server.xml,原配置文件是 <Connector connectionTimeout="20000" port="8080&qu ...