【项目创建流程】Gateway微服务网关
网关基本概念
1、API网关介绍
API 网关出现的原因是微服务架构的出现,不同的微服务一般会有不同的网络地址,而外部客户端可能需要调用多个服务的接口才能完成一个业务需求,如果让客户端直接与各个微服务通信,会有以下的问题:
(1)客户端会多次请求不同的微服务,增加了客户端的复杂性。
(2)存在跨域请求,在一定场景下处理相对复杂。
(3)认证复杂,每个服务都需要独立认证。
(4)难以重构,随着项目的迭代,可能需要重新划分微服务。例如,可能将多个服务合并成一个或者将一个服务拆分成多个。如果客户端直接与微服务通信,那么重构将会很难实施。
以上这些问题可以借助 API 网关解决。API 网关是介于客户端和服务器端之间的中间层,所有的外部请求都会先经过 API 网关这一层。也就是说,API 的实现方面更多的考虑业务逻辑,而安全、性能、监控可以交由 API 网关来做,这样既提高业务灵活性又不缺安全性
2、Spring Cloud Gateway
Spring cloud gateway是spring官方基于Spring 5.0和Spring Boot2.0等技术开发的网关,Spring Cloud Gateway旨在为微服务架构提供简单、有效和统一的API路由管理方式,Spring Cloud Gateway作为Spring Cloud生态系统中的网关,目标是替代Netflix Zuul,其不仅提供统一的路由方式,并且还基于Filer链的方式提供了网关基本的功能,例如:安全、监控/埋点、限流等。
3、Spring Cloud Gateway 核心概念
下面介绍一下Spring Cloud Gateway中几个重要的概念。
(1)路由。路由是网关最基础的部分,路由信息有一个ID、一个目的URL、一组断言和一组Filter组成。如果断言路由为真,则说明请求的URL和配置匹配
(2)断言。Java8中的断言函数。Spring Cloud Gateway中的断言函数允许开发者去定义匹配来自于http request中的任何信息,比如请求头和参数等。
(3)过滤器。一个标准的Spring webFilter。Spring cloud gateway中的filter分为两种类型的Filter,分别是Gateway Filter和Global Filter。过滤器Filter将会对请求和响应进行修改处理。
4、执行流程
如下图所示,Spring cloud Gateway发出请求。然后再由Gateway Handler Mapping中找到与请求相匹配的路由,将其发送到Gateway web handler。Handler再通过指定的过滤器链将请求发送到我们实际的服务执行业务逻辑,然后返回。
4、特点
优点:
- 性能强劲:是第一代网关Zuul的1.6倍
- 功能强大:内置了很多实用的功能,例如转发、监控、限流等
- 设计优雅,容易扩展
缺点:
- 其实现依赖Netty与WebFlux,不是传统的Servlet编程模型,学习成本高
- 不能将其部署在Tomcat、Jetty等Servlet容器里,只能打成jar包执行
- 需要Spring Boot 2.0及以上的版本,才支持
搭建Gateway服务
创建父模块infrastructure
创建子模块api_gateway
配置pom
在api_gateway的pom中添加如下依赖
<dependencies>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-gatewayartifactId>
dependency>
dependencies>
配置application.yml
server:
port: 9110 # 服务端口
spring:
profiles:
active: dev # 环境设置
application:
name: infrastructure-apigateway # 服务名
logback.xml
修改日志输出目录名为 apigateway
创建启动类
gataway依赖common,课是common引入了mybatisplus操作,所有有数据库操作,因此需要排除数据库操作
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class} )
package com.atguigu.guli.infrastructure.apigateway;
@SpringBootApplication
public class InfrastructureApiGatewayApplication {
public static void main(String[] args) {
SpringApplication.run(InfrastructureApiGatewayApplication.class, args);
}
}
启动网关
配置路由和跨域
1、路由和断言
application.yml文件中添加路由配置
- -:表示数组元素,可以配置多个节点
- id:配置的唯一标识,可以和微服务同名,也可以起别的名字,区别于其他 Route。
- uri:路由指向的目的地 uri,即客户端请求最终被转发到的微服务。
- predicates:断言的作用是进行条件判断,只有断言都返回真,才会真正的执行路由。
- Path:路径形式的断言。当匹配这个路径时,断言条件成立
- /**:一个或多个层次的路径
#spring:
cloud:
gateway:
routes:
- id: service-edu
uri: http://localhost:8110
predicates:
- Path=/user/**
内置路由断言工厂
Predicate(断言) 用于进行条件判断,只有断言都返回真,才会真正的执行路由。
SpringCloud Gateway包括许多内置的断言工厂,所有这些断言都与HTTP请求的不同属性匹配。具体如下:
1、基于Datetime
此类型的断言根据时间做判断,主要有三个:
- AfterRoutePredicateFactory: 接收一个日期参数,判断请求日期是否晚于指定日期
- BeforeRoutePredicateFactory: 接收一个日期参数,判断请求日期是否早于指定日期
- BetweenRoutePredicateFactory: 接收两个日期参数,判断请求日期是否在指定时间段内
- After=2019-12-31T23:59:59.789+08:00[Asia/Shanghai]
2、基于远程地址
RemoteAddrRoutePredicateFactory:接收一个IP地址段,判断请求主机地址是否在地址段中
- RemoteAddr=192.168.1.1/24
3、基于Cookie
CookieRoutePredicateFactory:接收两个参数,cookie 名字和一个正则表达式。 判断请求cookie是否具有给定名称且值与正则表达式匹配。
-Cookie=chocolate, ch.
4、基于Header
HeaderRoutePredicateFactory:接收两个参数,标题名称和正则表达式。 判断请求Header是否具有给定名称且值与正则表达式匹配。
-Header=X-Request-Id, \d+
5、基于Host
HostRoutePredicateFactory:接收一个参数,主机名模式。判断请求的Host是否满足匹配规则。
-Host=**.testhost.org
6、基于Method请求方法
MethodRoutePredicateFactory:接收一个参数,判断请求类型是否跟指定的类型匹配。
-Method=GET
7、基于Path请求路径
PathRoutePredicateFactory:接收一个参数,判断请求的URI部分是否满足路径规则。
- Path=/foo/**
8、基于Query请求参数
QueryRoutePredicateFactory :接收两个参数,请求param和正则表达式, 判断请求参数是否具有给定名称且值与正则表达式匹配。
-Query=url,baidu
9、基于路由权重
WeightRoutePredicateFactory:接收一个[组名,权重],然后对于同一个组内的路由按照权重转发
routes:
- id: weight_route1
uri: host1
predicates:
- Path=/product/**
- Weight=group3, 1
- id: weight_route2
uri: host2
predicates:
- Path=/product/**
- Weight= group3, 9
过滤器
一、过滤器的基本概念
1、作用
过滤器就是在请求的传递过程中,对请求和响应做一些修改
2、生命周期
客户端的请求先经过“pre”类型的filter,然后将请求转发到具体的业务服务,收到业务服务的响应之后,再经过“post”类型的filter处理,最后返回响应到客户端。
pre: 这种过滤器在请求被路由之前调用。我们可利用这种过滤器实现参数校验、权限校验、流量监控、日志输出、协议转换等;
post:这种过滤器在路由到达微服务以后执行。这种过滤器可用做响应内容、响应头的修改,日志的输出,流量监控等。
3、分类
局部过滤器 GatewayFilter:作用在某一个路由上
全局过滤器 GlobalFilter:作用全部路由上
二、局部过滤器
1、内置局部过滤器
在SpringCloud Gateway中内置了很多不同类型的网关路由过滤器。具体如下
routes:
- id: service-edu
uri: lb://service-edu
predicates:
- Path=/user/**, /*/edu/**
filters:
- SetStatus=250 # 修改返回状态码
测试:
三、全局过滤器
1、内置全局过滤器
内置全局过滤器的使用举例:负载均衡过滤器
lb://service-edu
2、自定义全局过滤器
定义一个Filter实现 GlobalFilter 和 Ordered接口
自定义转发路径
filters:
- RewritePath=/api/(?.*),/renren-fast/$\{segment}
2、测试网关路由转发
访问:http://localhost:9110/user/info
请求转发到:http://localhost:8110/user/info
通过nacos注册中心
1、网关中添加依赖
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
dependency>
2、主类添加注解
@EnableDiscoveryClient //SpringBoot2.0之后可以省略
3、添加nacos配置
#spring:
# cloud:
nacos:
discovery:
server-addr: localhost:8848 # nacos服务地址
4、添加gateway配置
#spring:
# cloud:
# gateway:
discovery:
locator:
enabled: true # gateway可以发现nacos中的微服务
5、修改uri配置
将uri的地址修改成注册中心中的微服务地址,网关姜葱nacos中按照名称获取微服务
lb:表示在集群环境下通过负载均衡的方式调用
uri: lb://service-edu #内置负载均衡过滤器
6、测试
访问:http://localhost:9110/user/info
7、匹配多个path
- Path=/user/**, /*/edu/**
跨域配置
1、前端配置
修改guli-admin中 config/dev.env.js,BASE_API指定到网关地址
BASE_API: '"http://127.0.0.1:9110"',
2、删除后端跨域配置
此时可以删除微服务中的跨域注解 @CrossOrigin
例如 service_edu中 LoginController的跨域注解
3、跨域配置
package com.atguigu.guli.infrastructure.apigateway.config;
@Configuration
public class CorsConfig {
@Bean
public CorsWebFilter corsFilter() {
CorsConfiguration config = new CorsConfiguration();
config.addAllowedMethod("*");
config.addAllowedOrigin("*");
config.addAllowedHeader("*");
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(new PathPatternParser());
source.registerCorsConfiguration("/**", config);
return new CorsWebFilter(source);
}
}
注意:去掉后端的所有跨域配置
完整的路由配置
yml配置
routes:
- id: service-edu
uri: lb://service-edu
predicates:
- Path=/user/**, /*/edu/**
- id: service-cms
uri: lb://service-cms
predicates:
- Path=/*/cms/**
- id: service-oss
uri: lb://service-oss
predicates:
- Path=/*/oss/**
- id: service-sms
uri: lb://service-sms
predicates:
- Path=/*/sms/**
- id: service-trade
uri: lb://service-trade
predicates:
- Path=/*/trade/**
- id: service-ucenter
uri: lb://service-ucenter
predicates:
- Path=/*/ucenter/**
- id: service-vod
uri: lb://service-vod
predicates:
- Path=/*/vod/**
前端配置
(1)修改guli-site中 utils/request.js,BASE_API指定到网关地址
baseURL: 'http://127.0.0.1:9110',
(2)所有的api模块中的baseURL可以删除
(3)guli-admin上传相关表单中action地址的修改
data中定义:
BASE_API: process.env.BASE_API
html中使用:
:action="BASE_API+'/admin/oss/file/upload?module=avatar'"