是什么

  • 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. salesforce零基础学习(一百一十一)custom metadata type数据获取方式更新

    本篇参考: https://developer.salesforce.com/docs/atlas.en-us.234.0.apexref.meta/apexref/apex_methods_syst ...

  2. 掌握这些常用Linux命令,一起提升工作效率

    开始上班了,新一年的奋斗的之路启程了,要继续[奔赴山海,奔赴热爱]. 汪国真在<热爱生命>这首诗中写到:既然选择了远方,便只顾风雨兼程.技术上还是持续精进和学习,远方虽远,要迈开脚步,一步 ...

  3. 支付宝同步请求检查appid,以及公钥,私钥是否正确

    第一步:下载支付宝Demo 下载地址:https://opendocs.alipay.com/open/270/106291#%E8%BF%90%E8%A1%8C%E8%AF%B4%E6%98%8E ...

  4. Redis 分布式锁使用不当,酿成一个重大事故,超卖了100瓶飞天茅台!!!(转)

    基于Redis使用分布式锁在当今已经不是什么新鲜事了. 本篇文章主要是基于我们实际项目中因为redis分布式锁造成的事故分析及解决方案.我们项目中的抢购订单采用的是分布式锁来解决的,有一次,运营做了一 ...

  5. VC里打开网页

    转载请注明来源:https://www.cnblogs.com/hookjc/ 1     ShellExecute 开放分类: API 编程 ShellExecute函数原型及参数含义如下: She ...

  6. axios取消接口请求

    axios取消请求 这里就是分析一下接口请求需要被取消时的一些操作 因为我是用vue写的项目,所以标配用的是axios,怎么在axios中取消已经发送的请求呢? 1.在这之前我们还是先介绍一下原生js ...

  7. MySQL-MMM高可用架构

    MySQL-MMM高可用架构 目录 MySQL-MMM高可用架构 一.MMM 1. MMM的概述 2. MMM的应用场景 3. MMM的特点 4. 关于MMM高可用架构的说明 5. 用户及授权 二.案 ...

  8. 备忘录——关于C#生成条形码

    目录 0. 背景说明 1. 使用ZXing.NET 2. 使用BarcodeLib 3. 使用字体 4. 参考 志铭-2022年2月15日 22:15:46 0. 背景说明 在.net程序中生成69码 ...

  9. 3、Linux基础--cp、mv、rm、alias、vi/vim命令

    笔记 1.考试 1.判断网络是否通畅的命令 ping 2.定义系统提示组成的变量 PS1 3.Linux中目录从什么开始 根(/) 4.系统中目录路径类型有哪些,解释一下 绝对路径:以根目录作为参照物 ...

  10. Netty高级应用及聊天室实战

    Netty 高级应用 1. 编解码器 概念:在网络应用中,需要实现某种编解码器.将原始字节数据与自定义消息数据进行相互转换.网络中都是以字节码的形式传输的. 对Netty而言,编解码器由两部分组成:编 ...