提示:定制软件写完文章后,定制软件目录可以自动生成,定制软件如何生成可参考右边的帮助文档
文章目录
前言
提示:定制软件这里可以添加本文要记定制软件录的大概内容:
定制软件前面介绍了Spring Cloud集中的Dubbo和Seata框架,以及Sentinel定制软件框架保障服务器运行的稳定性。定制软件本文将介绍SpringGateway网关框架。
提示:定制软件以下是本篇文章正文内容,定制软件下面案例可供参考
一、什么是
"网"指网络,"关"定制软件指关口或关卡
网关:定制软件就是指网络中的关口\关卡
定制软件网关就是当前微服务项目的"统一入口"
定制软件程序中的网关就是当前定制软件微服务项目对外界开放定制软件的统一入口
定制软件所有外界的请求都需要定制软件先经过网关才能访问到定制软件我们的程序
定制软件提供了统一入口之后,定制软件方便对所有请求进行统定制软件一的检查和管理
网关的主要功能有
- 将所有请求统一经过网关
- 网关可以对这些请求进行检查
- 网关方便记录所有请求的日志
- 网关可以统一将所有请求路由到正确的模块\服务上
二、 Spring Gateway简介
使用Spring Gateway作为项目的网关框架。
Spring Gateway是Spring自己编写的,也是SpringCloud中的组件。
SpringGateway官网
网关项目git地址
1、简单网关演示
SpringGateway网关是一个依赖,不是一个软件
所以我们要使用它的话,必须先创建一个SpringBoot项目
这个项目也要注册到Nacos注册中心,因为网关项目也是微服务项目的一个组成部分
beijing和shanghai是编写好的两个项目
gateway项目就是网关项目,需要添加相关配置
<dependencies> <!-- Gateway依赖 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency> <!-- Nacos依赖 --> <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></dependencies>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
下面对当前项目所有服务器添加路由配置信息
server: port: 9000spring: application: name: gateway cloud: nacos: discovery: # 网关也是微服务项目的一部分,所以也要注册到Nacos server-addr: localhost:8848 gateway: # routes是一个数组,数组中的数据使用"-"开头表示数据中的一个对象 routes: # 开始编写Gateway路由配置 # 当前路由的名称,和任何其他名称没有关联,只是不能和后面再出现的路由名称重复 - id: gateway-beijing # 当匹配当前路由设置时,访问指定的服务器名称(Nacos注册的服务器名称) # lb是LoadBalance的缩写,是负载均衡的调用 uri: lb://beijing # 编写断言配置,断言的意思就是满足指定条件时运行某些事情 # predicates:断言 predicates: # 断言中我们编写当路径满足指定条件时 # 当请求路径以/bj/开头时,就会路由到上面设置好的beijing服务器运行 # ↓ P大写!!!!!!!! - Path=/bj/** #下面上海服务器配置类似 - id: gateway-shanghai uri: lb://shanghai predicates: - Path=/sh/**
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
上面的yml配置了bejing和shanghai项目的路由信息
我们使用
http://localhost:9000/bj/show可以访问beijing服务器的资源
http://localhost:9000/sh/show可以访问shanghai服务器的资源
以此类推,再有很多服务器时,我们都可以仅使用9000端口号来将请求路由到正确的服务器
就实现了gateway成为项目的统一入口的效果
2、动态路由
网关项目随着微服务数量的增多
gateway项目的yml文件配置会越来越多,维护的工作量也会越来越大
所以我们希望gateway能够设计一套默认情况下自动路由到每个模块的路由规则
这样的话,不管当前项目有多少个路由目标,都不需要维护yml文件了
这就是我们SpringGateway的动态路由功能
配置文件中开启即可
server: port: 9000spring: application: name: gateway cloud: nacos: discovery: # 网关也是微服务项目的一部分,所以也要注册到Nacos server-addr: localhost:8848 gateway: discovery: locator: # 这是开启动态路由的配置,动态路由设置默认是不开启的 也就是enabled: false # 路由规则是在网关端口号后,先写路由目标注册到nacos的名称,再编写具体路径 # localhost:9000/beijing/bj/show enabled: true
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
路由规则是在9000端口号后面先编写路由目标项目注册到nacos的名称,再编写具体路径。使用
localhost:9000/beijing/bj/show 可以访问beijing服务器的资源
localhost:9000/shanghai/sh/show可以访问shanghai服务器的资源
3、内置断言
之前在网关配置中使用了predicates(断言)的配置
断言的意思就是判断某个条件是否满足
我们之前使用了Path断言,判断请求的路径是不是满足条件,例如是不是/sh/** /bj/**
如果路径满足这个条件,就路由到指定的服务器
但是Path实际上只是SpringGateway提供的多种内置断言中的一种
还有很多其它断言
- after
- before
- between
- cookie
- header
- host
- method
- path
- query
- remoteaddr
具体使用方法参考官方文档
4、内置过滤器
Gateway还提供的内置过滤器
不要和我们学习的filter混淆
内置过滤器允许我们在路由请求到目标资源的同时,对这个请求进行一些加工或处理。
三、csmall项目网关
下面是我自己的微服务项目配置网关流程,供参考
1、创建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> <relativePath/> <!-- lookup parent from repository --> </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> <!-- web实例 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- Nacos注册依赖 --> <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-gateway</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-loadbalancer</artifactId> </dependency> <dependency> <groupId>com.github.xiaoymin</groupId> <artifactId>knife4j-spring-boot-starter</artifactId> </dependency> </dependencies></project>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
也删除test测试文件夹
application.properties换为yaml
配置如下
server: port: 19000spring: application: name: gateway cloud: nacos: discovery: server-addr: localhost:8848 gateway: discovery: locator: # 开启动态路由 enabled: true main: web-application-type: reactive
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
2、网关项目的knife4j配置
我们希望配置网关之后,在使用knife4j测试时
就不来回切换端口号了
我们需要在网关项目中配置Knife4j才能实现
而这个配置是固定的,
只要是网关项目配置各个子模块的knife4j功能,就直接复制这几个类即可
在gateway项目中创建config包
SwaggerProvider
@Componentpublic 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; }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
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))); }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
cn.tedu.gateway.filter
SwaggerHeaderFilter类
@Componentpublic 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); }; }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
测试网关路由效果,和knife4j效果
启动Nacos\\Sentinel
启动cart\stock\order\business
最后启动gateway
可以通过19000端口测试各个业务模块的功能
http://localhost:19000/nacos-stock/doc.html
http://localhost:19000/nacos-cart/doc.html
http://localhost:19000/nacos-order/doc.html
http://localhost:19000/nacos-business/doc.html
如果不使用网关一切正常,但是启动网关访问失败的话,就是gateway项目配置问题
3、Gateway和SpringMvc依赖冲突问题和解决
之前网关的演示项目我们添加的网关依赖
<!-- Spring Gateway 网关依赖 --><dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId></dependency>
- 1
- 2
- 3
- 4
- 5
当前csmall项目需要配置knife4j的路由配置,需要编写一个控制器
所以我们添加了SpringMvc的依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId></dependency>
- 1
- 2
- 3
- 4
这两个依赖在同一个项目中时,默认情况下启动会报错
SpringMvc框架中自带一个Tomcat服务器
而SpringGateway框架中自带一个Netty的服务器
在启动项目时,两个框架中包含的服务器都想占用相同端口,因为争夺端口号和主动权而发生冲突
导致启动服务时报错
要想能够正常启动必须在yml文件配置
spring: main: web-application-type: reactive
- 1
- 2
- 3
reactive:反应的
添加这个配置之后,会Tomcat服务器会变成非阻塞的运行
总结
提示:这里对文章进行总结:
以上就是今天要讲的内容,介绍了SpringGateway网关在项目中的应用和配置。