是什么

  • 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

  1. Zuul 1.X,是一个基于阻塞I/O的API
  2. Zuul 1.X基于Servlet2.5使用阻塞架构它不支持任何长链接(如:WebSocket)Zuul的设计模式和Nginx较像,每次I/O操作都是从工作线程中选择一个执行,请求线程被阻塞到工作线程完成,但是差别是Nginx用C++实现,Zuul用Java实现,而JVM本身会有第一次加载较慢的情况,使的Zuul的性能相对较差
  3. Zuul 2.X理念更先进,想基于Netty非阻塞和支持长连接,但SpringCloud目前还没有整合。Zuul 2.X的性能较Zuul 1.X有较大的提升,在性能方面,根据官方提供的基准测试,SpringCloud Gateway的RPS(每秒请求数)是Zuul的1.6倍
  4. SpringCloud Gateway 建立在Spring Framework 5 、ProjectReactor和SpringBoot 2之上,使用非阻塞API
  5. 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配置使用的更多相关文章

  1. Spring Gateway配置使用(一)

    参考文档:Spring Gateway官方文档 , 玹霖的博客 1.Spring Gateway简介 Spring Cloud Gateway是Spring官方基于Spring 5.0,Spring ...

  2. zabbix java gateway配置实战案例

    zabbix java gateway配置实战案例 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.部署tomcat服务 博主推荐阅读: CentOS: https://www. ...

  3. 【SpringCloud】Gateway 配置全局过滤器获取请求参数和响应值

    [SpringCloud]Gateway 配置全局过滤器获取请求参数和响应值 实现Ordered接口getOrder()方法,数值越小越靠前执行,记得这一点就OK了. 获取请求参数RequestBod ...

  4. 使用Gateway配置路由以及动态路由

    1. 新建module cloud-gateway-gateway9527 2. pom.xml <!--注意不需要web模块依赖,否则报错--> <?xml version=&qu ...

  5. Springcloud之gateway配置及swagger集成

    前言 关于引入gateway的好处我网上找了下: 性能:API高可用,负载均衡,容错机制. 安全:权限身份认证.脱敏,流量清洗,后端签名(保证全链路可信调用),黑名单(非法调用的限制). 日志:日志记 ...

  6. Layer 创建 和 lamdba function 创建 和 API GateWay 配置 和 添加依赖

    进入控制台 选择 Lamdba 服务 进入控制面板, 单击右边: 创建函数 然后进入此图界面 添加lamdba 函数 名称 选择运行环境:python 选择角色 选择现有角色, 角色创建 可以参考 无 ...

  7. gateway 配置

    server: port: spring: application: name: api-gateway eureka: client: service-url: defaultZone: http: ...

  8. 学习一下 SpringCloud (六)-- 注册中心与配置中心 Nacos、网关 Gateway

    (1) 相关博文地址: 学习一下 SpringCloud (一)-- 从单体架构到微服务架构.代码拆分(maven 聚合): https://www.cnblogs.com/l-y-h/p/14105 ...

  9. [译]How to Setup Sync Gateway on Ubuntu如何在ubuntu上安装sync-gateway

    参考文章https://hidekiitakura.com/2015/03/21/how-to-setup-sync-gateway-on-ubuntudigitalocean/ 在此对作者表示感谢 ...

随机推荐

  1. RPC和REST的区别

    REST定义 REST是一种架构风格,指的是一组架构约束条件和原则.满足这些约束条件和原则的应用程序或设计就是 RESTful.REST规范把所有内容都视为资源,网络上一切皆资源.REST并没有创造新 ...

  2. NFS(Network File System)即网络文件系统 (转)

    第1章 NFS介绍 1.1 NFS服务内容的概述 □ RPC服务知识概念介绍说明,以及RPC服务存在价值(必须理解掌握) □ NFS服务工作原理讲解(必须理解掌握) □ NFS共享文件系统使用原理讲解 ...

  3. CABasicAnimation动画

    使用CABasicAnimation动画: CALayer *znzLayer; = [[CALayer alloc]init]; //创建不断该表CALayer的transform属性动画 CABa ...

  4. K8s二进制部署单节点 master组件 node组件 ——头悬梁

    K8s二进制部署单节点   master组件 node组件   --头悬梁 1.master组件部署 2.node   组件部署 k8s集群搭建: etcd集群 flannel网络插件 搭建maste ...

  5. Docker之LNMP分布式容器部署

    Docker之LNMP分布式容器部署 目录 Docker之LNMP分布式容器部署 一.项目模拟 1. 项目环境 2. 服务器环境 3. 任务需求 二.Linux系统基础镜像 三.Nginx 1. 建立 ...

  6. Shell条件练习题

    Shell条件练习题 目录 Shell条件练习题 1.检查用户家目录中的 test.sh 文件是否存在,并且检查是否有执行权限 2.提示用户输入100米赛跑的秒数,要求判断秒数大于0且小于等于10秒的 ...

  7. ubuntu Python2 升级Python3

    今天买了一台阿里的服务器, 想搭建一个爬虫, 但是 服务器是python2的, 需要升级到python3 1. 下载python3的包 wget https://www.python.org/ftp/ ...

  8. 4、网络并发编程--僵尸进程、孤儿进程、守护进程、互斥锁、消息队列、IPC机制、生产者消费者模型、线程理论与实操

    昨日内容回顾 操作系统发展史 1.穿孔卡片 CPU利用率极低 2.联机批处理系统 CPU效率有所提升 3.脱机批处理系统 CPU效率极大提升(现代计算机雏形) 多道技术(单核CPU) 串行:多个任务依 ...

  9. Solution -「51nod 1355」斐波那契的最小公倍数

    \(\mathcal{Description}\)   Link.   令 \(f\) 为 \(\text{Fibonacci}\) 数列,给定 \(\{a_n\}\),求: \[\operatorn ...

  10. 华为云企业级Redis揭秘第16期:超越开源Redis的ACID"真"事务

    摘要: 开源Redis只支持伪事务,应用场景受限.高斯Redis发布企业级事务特性,支持完备ACID,为交易.库存等上层业务带来全新可能. 本文分享自华为云社区<华为云企业级Redis揭秘第16 ...