SpringGateway 网关

奈非框架简介

早期(2020年前)奈非提供的微服务组件和框架受到了很多开发者的欢迎

这些框架和Spring Cloud Alibaba的对应关系我们要知道

Nacos对应Eureka 都是注册中心

Dubbo对应ribbon+feign都是实现微服务间调用

Sentinel对应Hystrix都是项目限流熔断降级组件

Gateway对应zuul都是项目的网关

Gateway不是阿里巴巴的而是Spring提供的

什么是网关

"网关"网是网络,关是关口\关卡

关口\关卡的意思就是"统一入口"

网关:就是网络中的统一入口

程序中的网关就是微服务项目提供的外界所有请求统一访问的微服务项目

因为提供了统一入口之后,方便对所有请求进行统一的检查和管理

网关的主要功能有

  • 将所有请求统一由经过网关
  • 网关可以对这些请求进行检查
  • 网关方便记录所有请求的日志
  • 网关可以统一将所有请求路由到正确的模块\服务上

路由的近义词就是"分配"

Spring Gateway简介

我们使用Spring Gateway作为当前项目的网关框架

Spring Gateway是Spring自己编写的,也是SpringCloud中的组件

SpringGateway官网

https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/

网关项目git地址

https://gitee.com/jtzhanghl/gateway-demo.git

简单网关演示

网关是一个我们创建的项目,不是一个需要安装的软件

网关也是当前微服务项目的一员,也要注册到Nacos,所以保证Nacos的运行

运行之前,我们看一下网关演示项目已经存在的基本结构

beijing和shanghai是编写好的两个项目

gateway没有编写yml文件配置

要想实现网关的路由效果需要修改yml文件如下

server:
port: 9000
spring:
application:
name: gateway
cloud:
nacos:
discovery:
server-addr: localhost:8848
gateway:
routes: # gateway开始配置路由信息
- id: gateway-shanghai
uri: lb://shanghai
predicates:
- Path=/sh/**
# 如果java访问这个数字元素的方式:spring.cloud.gateway.routes[0].predicates[0]
# routes属性实际上是一个数组,yml文件中出现 "- ...."配置时表示当前配置时一个数组元素
- id: gateway-beijing # 这个配置指定这个路由的名称,这个名称和其他任何位置没有关联
# 只需要注意不能再和其他路由名称重复
# uri设置路由的目标
# lb是LoadBalance(负载均衡)的缩写,beijing是注册到nacos的服务名称
uri: lb://beijing
# 我们需要设置一个条件,当访问路径满足特定条件是,使用当前路由规则
predicates:
# predicates翻译为断言,所谓断言就是判断一个条件是否满足
# Path 是路径断言,意思是满足路径为XXX时使用这个路由
- Path=/bj/**
# http://localhost:9000/bj/show 会路由到 9001/bj/show

内置断言

断言就是判断一个条件,如果条件满足就执行某个操作

predicates就是断言的意思

我们前面章节使用的Path就是内置断言中的一种,指访问的路径是否满足条件

除了路径断言之外,还有很多内置断言常见的内置断言列表

  • after
  • before
  • between
  • cookie
  • header
  • host
  • method
  • path
  • query
  • remoteaddr

时间相关

after,before,between

在指定时间之后,之前或之间

判断是否满足时间条件,如果满足才允许访问

我们先使用下面代码获得当前包含时区的系统时间表

ZonedDateTime.now()

使用After设置必须在指定时间之后访问

- id: gateway-shanghai
uri: lb://shanghai
predicates:
- Path=/sh/**
- After=2022-06-24T15:30:30.999+08:00[Asia/Shanghai]

使用Before设置必须在指定时间之后访问

- id: gateway-shanghai
uri: lb://shanghai
predicates:
- Path=/sh/**
- Before=2022-06-24T15:34:00.999+08:00[Asia/Shanghai]

使用Between设置必须在指定时间之间访问

- id: gateway-shanghai
uri: lb://shanghai
predicates:
- Path=/sh/**
- Between=2022-06-24T15:34:00.999+08:00[Asia/Shanghai],2022-06-24T15:36:20.999+08:00[Asia/Shanghai]

要求指定参数

Query断言,要求必须包含指定的参数才能访问资源

- id: gateway-shanghai
uri: lb://shanghai
predicates:
- Path=/sh/**
- Query=name

内置过滤器

Gateway还提供的内置过滤器

不要和我们学习的filter混淆

内置过滤器允许我们在路由请求到目标资源的同时,对这个请求进行一些加工或处理

下面我们使用AddRequestParameter过滤器,想请求中添加参数

- id: gateway-shanghai
uri: lb://shanghai
predicates:
- Path=/sh/**
- Query=name
filters:
- AddRequestParameter=age,80

shanghai项目的控制器接收这个参数

@GetMapping("/show")
public String show(String name,Integer age){
return "这里是上海!"+name+","+age;
}

重启网关和shanghai项目

例如输入如下路径

http://localhost:9000/sh/show?name=tom

因为过滤器的存在,控制可以获取网关过滤器添加的参数值

其他内置过滤器和自定义过滤器的使用,同学们可以查阅相关文档自己了解

动态路由

如果项目微服务数量多

那么gateway项目yml文件配置也会越来越冗余,维护的工作量也会越来越大

所谓我们希望能够根据固定特征自动的路由到每个微服务模块

这个功能就是SpringGateway的动态路由功能

只需要在配置文件中配置开启动态路由功能即可

spring:
application:
name: gateway
cloud:
nacos:
discovery:
server-addr: localhost:8848
gateway:
discovery:
locator:
# 开启Spring Gateway的动态路由功能
# 规则是根据注册到Nacos的项目名称作为路径的前缀,就可以访问到指定项目了
enabled: true

开启之后访问项目的格式以beijing为例

localhost:9000/beijing/bj/show

csmall项目网关

创建gateway网关子项目

父子相认

子项目pom文件为

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>cn.tedu</groupId>
<artifactId>csmall</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<groupId>cn.tedu</groupId>
<artifactId>gateway</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>gateway</name>
<description>Demo project for Spring Boot</description> <dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- 网负载均衡支持 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
<!-- Spring Gateway 网关依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!--聚合网关 knife4j-->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
</dependency>
</dependencies>
</project>

也删除test测试文件夹

application.yml文件内容如下

spring:
application:
name: gateway-server
cloud:
nacos:
discovery:
server-addr: localhost:8848
gateway:
discovery:
locator:
# 开启网关动态路由
enabled: true
main:
web-application-type: reactive
server:
port: 10000

knife4j网关配置

我们希望配置网关之后,在使用knife4j测试时

就不来回切换端口号了

我们需要配置Knife4j才能实现

创建包cn.tedu.gateway.config包

SwaggerProvider

@Component
public class SwaggerProvider implements SwaggerResourcesProvider {
/**
* 接口地址
*/
public static final String API_URI = "/v2/api-docs";
/**
* 路由加载器
*/
@Autowired
private RouteLocator routeLocator;
/**
* 网关应用名称
*/
@Value("${spring.application.name}")
private String applicationName; @Override
public List<SwaggerResource> get() {
//接口资源列表
List<SwaggerResource> resources = new ArrayList<>();
//服务名称列表
List<String> routeHosts = new ArrayList<>();
// 获取所有可用的应用名称
routeLocator.getRoutes().filter(route -> route.getUri().getHost() != null)
.filter(route -> !applicationName.equals(route.getUri().getHost()))
.subscribe(route -> routeHosts.add(route.getUri().getHost()));
// 去重,多负载服务只添加一次
Set<String> existsServer = new HashSet<>();
routeHosts.forEach(host -> {
// 拼接url
String url = "/" + host + API_URI;
//不存在则添加
if (!existsServer.contains(url)) {
existsServer.add(url);
SwaggerResource swaggerResource = new SwaggerResource();
swaggerResource.setUrl(url);
swaggerResource.setName(host);
resources.add(swaggerResource);
}
});
return resources;
}
}

cn.tedu.gateway.controller

SwaggerController类

@RestController
@RequestMapping("/swagger-resources")
public class SwaggerController {
@Autowired(required = false)
private SecurityConfiguration securityConfiguration;
@Autowired(required = false)
private UiConfiguration uiConfiguration;
private final SwaggerResourcesProvider swaggerResources;
@Autowired
public SwaggerController(SwaggerResourcesProvider swaggerResources) {
this.swaggerResources = swaggerResources;
}
@GetMapping("/configuration/security")
public Mono<ResponseEntity<SecurityConfiguration>> securityConfiguration() {
return Mono.just(new ResponseEntity<>(
Optional.ofNullable(securityConfiguration).orElse(SecurityConfigurationBuilder.builder().build()), HttpStatus.OK));
}
@GetMapping("/configuration/ui")
public Mono<ResponseEntity<UiConfiguration>> uiConfiguration() {
return Mono.just(new ResponseEntity<>(
Optional.ofNullable(uiConfiguration).orElse(UiConfigurationBuilder.builder().build()), HttpStatus.OK));
}
@GetMapping("")
public Mono<ResponseEntity> swaggerResources() {
return Mono.just((new ResponseEntity<>(swaggerResources.get(), HttpStatus.OK)));
}
}

cn.tedu.gateway.filter

SwaggerHeaderFilter类

@Component
public class SwaggerHeaderFilter extends AbstractGatewayFilterFactory {
private static final String HEADER_NAME = "X-Forwarded-Prefix"; private static final String URI = "/v2/api-docs"; @Override
public GatewayFilter apply(Object config) {
return (exchange, chain) -> {
ServerHttpRequest request = exchange.getRequest();
String path = request.getURI().getPath();
if (!StringUtils.endsWithIgnoreCase(path,URI )) {
return chain.filter(exchange);
}
String basePath = path.substring(0, path.lastIndexOf(URI));
ServerHttpRequest newRequest = request.mutate().header(HEADER_NAME, basePath).build();
ServerWebExchange newExchange = exchange.mutate().request(newRequest).build();
return chain.filter(newExchange);
};
}
}

启动Nacos\Seata\Sentinel

启动cart\stock\order\business

在保证一般访问正常的情况下

再启动gateway

可以通过下面路径访问之前的各个模块的业务

http://localhost:10000/nacos-stock/doc.html

http://localhost:10000/nacos-cart/doc.html

http://localhost:10000/nacos-order/doc.html

http://localhost:10000/nacos-business/doc.html

如果不使用网关一切正常,但是启动网关访问失败的话,就是gateway项目配置问题

Gateway和SpringMvc依赖冲突问题和解决

网关依赖

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>

SpringMvc依赖

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

这两个依赖在同一个项目中时,默认情况下启动会报错

SpringMvc依赖中自带一个Tomcat服务器

而Gateway依赖中自带一个Netty服务器

因为在启动服务时这个两个服务器都想启动,会因为争夺端口号和主动权而发生冲突

我们需要在yml文件中添加配置解决

spring:
main:
web-application-type: reactive

Elasticsearch概述

什么是Elasticsearch

elastic:富有弹性的

search:搜索

在计算机开发界简称ES

这个软件不是SpringCloud的组件,甚至其他语言都可以使用它

是一个java开发的软件,所以启动需要java环境变量

功能是从大量数据中根据指定的关键字搜索出匹配的结果

这样的软件有一个名称全文搜索引擎

使用它的方式是访问它提供的控制器方法,它开发了多种控制器方法

访问不同方法实现对数据的增删改查

ES也是将数据保存在硬盘上的

常见面试题ES的实现结构

java有一套名为Lucene的API

是搜索引擎的核心支持,Elasticsearch在Lucene的基础上开发出了一个功能全面的开箱即用的全文搜索引擎

市面上ES的竞品有

Solr/MongoDB

为什么使用Elasticsearch

因为我们之前学习的所有关系型数据库都有一个严重的性能缺陷

mysql\mariaDB\oracle\DB2等

就是前模糊的模糊查询不能使用索引

select * from spu where spu_name like '%鼠标%'

测试证明一张千万级别的数据库表进行模糊查询需要20秒以上

当今需求"三高"的需求下,不能接受这样的性能

我们使用ES来优化后同样的查询我们能将效率提高100倍

将大型的查询也能控制在毫秒级别

Elasticsearch查询原理

如果不使用ES让数据库查询,没有索引加持的模糊查询就是全表搜索性能差

但是Elasticsearch可以利用添加数据库完成对数据的分词倒排索引形成索引库

在查询时直接查询索引库,获得符合查询条件的数据信息

5-5 SpringGateway 网关的更多相关文章

  1. spring cloud 2.x版本 Gateway路由网关教程

    前言 本文采用Spring cloud本文为2.1.8RELEASE,version=Greenwich.SR3 本文基于前两篇文章eureka-server.eureka-client.eureka ...

  2. API网关才是大势所趋?SpringCloud Gateway保姆级入门教程

    什么是微服务网关 SpringCloud Gateway是Spring全家桶中一个比较新的项目,Spring社区是这么介绍它的: 该项目借助Spring WebFlux的能力,打造了一个API网关.旨 ...

  3. 前端学HTTP之网关、隧道和中继

    前面的话 Web是一种强大的内容发布工具.人们已经从只在网上发送静态的在线文档,发展到共享更复杂的资源,比如数据库内容或动态生成的HTML页面.Web浏览器为用户提供了一种统一的方式来访问因特网上的内 ...

  4. IP地址,子网掩码,默认网关,DNS服务器知识详解(转)

    转自:http://www.cnblogs.com/JuneWang/p/3917697.html 为了更深入的学习TCP/IP协议,最近看了不少有关资料,收集整理记录如下,以备后面的使用和方便各位学 ...

  5. 如何为RD网关创建自建签名的证书

    创建安全的RD网关是一件非常好的事情,这样可以在公网环境下直接远程接入内部的已开启远程访问的主机服务器. 建立这个安全的RD网关需要的材料有RD网关本身,以及一个证书.由于一般情况下这些在RD网关后面 ...

  6. 用API网关把API管起来

    最开始只是想找个API网关防止API被恶意请求,找了一圈发现基于Nginx的OpenResty(Lua语言)扩展模块Orange挺好(也找了Kong,但是感觉复杂了点没用),还偷懒用Vagrant结合 ...

  7. TCP/IP协议中网关和子网掩码概念

    网关: 不同网段的IP是不能直接互通的,需要一个设备来转发,这个设备就是网关,一般就是路由器,那么路由器的地址就是网关地址. 比如192.168.2.31要往192.168.3.31发送一条消息,他们 ...

  8. IP地址,子网掩码、默认网关,DNS服务器是什么意思?

    (一)  问题解析001.   问:  IP地址,子网掩码,默认网关,DNS服务器,有什么区别呀?我知道没有IP地址就不能上网,我也知道没设DNS就不能上外网,可它们都有什么功能,有什么区别呢?还有真 ...

  9. IP地址,子网掩码,默认网关,DNS服务器详解

    为了更深入的学习TCP/IP协议,最近看了不少有关资料,收集整理记录如下,以备后面的使用和方便各位学习: IP地址,子网掩码,默认网关,DNS服务器是什么意思? (一)  问题解析 001.   问: ...

随机推荐

  1. FreeRTOS --(1)链表

    转载自 https://blog.csdn.net/zhoutaopower/article/details/106550648 Based On FreeRTOS Kernel V10.3.1 1. ...

  2. Excel文件读写操作1(xls)

    一.Python-Excel常用的库:xlrd(read).xlwt(write).xlutils.openpyxl 1.xlrd  读取Excel文件,支持 .xls 和 .xlsx 格式. 2.x ...

  3. Linux网络重点知识总结性梳理

    一个执着于技术的公众号 1 OSI七层模型 层次 说明 功能/协议 应用层 应用程序及接口 提供应用程序的接口:FTP telnet http pop3等 表示层 对数据进行转换.加密和压缩 将上层的 ...

  4. 文本框字符限制、focus光标定位

    一.为一个元素的所有子元素设置统一样式:.className * { color: #6666 } 二.正则表达式: 1.去除所有HTML标签只保留文字: /<\/?.+?\/?>/2.去 ...

  5. 手脱PESpin壳【06.exe】

    1.查壳 2.LoradPE工具检查 一方面可以用LoradPE工具查看重定位,另一方面也可获取一些详细信息 3.查找OEP ①未发现pushad 开始未发现pushad,进行单步步入,很快就能找到p ...

  6. Border性质习题与证明

    KMP 第一次接触 \(border\) 都是先从 KMP 开始的吧. 思想在于先对于一个串自匹配以求出 fail 指针(也就是 border) 然后就可以在匹配其他串的时候非常自然的失配转移.在此顺 ...

  7. 关于『HTML5』第一弹

    关于『HTML5』:第一弹 建议缩放90%食用 祝各位国庆节快乐!!1 经过了「过时的 HTML」.「正当时的 Markdown」的双重洗礼后,我下定决心,好好学习HTML5  这回不过时了吧(其实和 ...

  8. React简单教程-4.1-hook

    前言 虽然我们简单感受了一下 useState 的用法,但我想你还是对 React 里的 hook 迷迷糊糊的.本文我们将明确下 React 的概念. HOOK 前生今世 在我示例中,写的 React ...

  9. 微前端(qiankun)主应用共享React组件

    前言 最近需要重构一个老项目,定的方案用微前端去改造.主应用是老的项目,微应用是新的项目,由于重构时间比较紧张,子应用还需要使用父应用的一些组件.过程中遇到一些问题,记录一下. 方案 我们知道qian ...

  10. 一个全新的Vue拖拽特性实现:“移动”部分

    关于拖拽 CabloyJS提供了完备的拖拽特性,可以实现移动和调整尺寸两大类功能,这里对移动的开发进行阐述 关于调整尺寸的开发,请参见:拖拽:调整尺寸 演示 开发步骤 下面以模块test-party为 ...