1.概念:
Gateway 微服务中间件,网关就像整个微服务系统的门面一样,是系统对外的唯一入口。有了它,客户端会先将请求发送到 API 网关,然后由 API 网关根据请求的标识信息将请求转发到微服务实例。
2.为什么要使用gateway?
在微服务架构中,一个系统往往由多个微服务组成,而这些服务可能部署在不同机房、不同地区、不同域名下。同时,在需要登录认证、授权方面的信息无法在各服务之间共享,以及可能存在跨域等问题就出现了,这个时候就可以通过 API 网关来解决这些问题。
3.工作原理
客户端向 Spring Cloud 网关发出请求。如果网关处理程序映射确定请求与路由匹配,则会将其发送到网关 Web 处理程序。 此处理程序通过特定于请求的筛选器链运行请求。 筛选器用虚线划分的原因是筛选器可以在发送代理请求之前和之后运行逻辑。 执行所有“预”过滤器逻辑。然后发出代理请求。发出代理请求后,将运行“post”筛选器逻辑。
搭建过程省略,项目结果图如下:
其中使用了nacos服务治理和feign远程调用服务,其使用在我之前的笔记中已经详细记录了
Spring cloud 集成nacos实现服务注册、发现和调用 — 详细笔记
spring cloud nacos配置管理— 学习笔记
Spring cloud ---- openfeign实现远程调用 学习笔记
在gateway的工程里面的application.yml文件中配置:
参考官网
我的配置如下:
server:
port: 7777
spring:
application:
name: gatewayService
cloud:
# gateway也是一个服务,也需要注册到nacos中心
nacos:
server-addr: localhost:8848
# 在这里配置gateway的配置
gateway:
# 路由信息,
routes:
# 路由id,唯一,自定义,尽量和对应的服务名称相联系
- id: order-service
# 服务的uri,lb代表负载均衡,
uri: lb://orderserver
# 路由断言,意思是满足这个下面的断言才能进行路由转发到对应的服务
predicates: # 相关的配置后面在看
- Path=/orders/**
- id: user-service
uri: lb://userserver
predicates:
- Path=/user/**
default-filters:
global-filter:
官网断言工厂地址
满足自己设置的所有的断言才能转发到对应的服务上去。
从下图可以看到一共12个断言,跑2个试试,剩下的用到了再去官网看就行
路径路由断言工厂
路由匹配规则,如:- Path=/orders/** 则代表请求当中携带orders就可以。
多个匹配规则用逗号隔开之间,如下:
spring:
cloud:
gateway:
routes:
- id: path_route
uri: https://example.org
predicates:
# 这里需要满足携带red以及有一个参数在,形如:/red/1
- Path=/red/{segment},/blue/{segment}
作用:设置请求的时间要在某个时间区间内
spring:
cloud:
gateway:
routes:
- id: between_route
uri: https://example.org
predicates:
# [America/Denver]这个代表美国时区, Asia/Shanghai 代表中国上海
- Between=Between=2017-01-20T17:42:47.443+08:00[Asia/Shanghai], 2023-02-26T08:00:00.443+08:00[Asia/Shanghai]
图中的时间是在2017.1.20的17:42:47到2023-02-26的08:00:00这个时间范围内,而从图中看到我此时的时间是2023-2-26的10:58已经不在这个时间范围内了,下面测试一下
结果:
显示404,没有数据说明没有转发到对应的服务去,下面我再改成在这个时间戳的
改到了2-28,在进行测试
还是举例使用2个,剩下的看一下,在需要的时候去官网看
官网路由过滤器工厂地址
在请求头里面添加参数
server:
port: 7777
spring:
application:
name: gatewayService
cloud:
nacos:
server-addr: localhost:8848
gateway:
routes:
- id: order-service
uri: lb://orderserver
predicates:
- Path=/orders/**
- Between=2017-01-20T17:42:47.443+08:00[Asia/Shanghai], 2023-02-28T08:00:00.443+08:00[Asia/Shanghai]
filters:
# 这就是在请求头里面放了一个myHeader,里面的值为20020305
- AddRequestHeader=myHeader,20020305
- id: user-service
uri: lb://userserver
predicates:
- Path=/user/**
重启相关的服务后,在controller里面取出这个值,看是否能取到
和上面的有点像,都是在请求里面加东西然后再发送到对应的服务上去
从controller取出值
默认过滤器就所有的路由都会执行
效果和默认过滤器一样,所有的router都要经过这个过滤器,但是这个是需要我们自己去实现这个过滤器的方法的:实现GlobalFilter 接口
MyGlobalFilterConfig:
package space.lkiku.config;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
/**
* @Classname MyGlobalFilter
* @Description TODO Gateway全局过滤器
* @Version 1.0.0
* @Date 2023/2/26 14:31
* @Created by wlh12
*/
@Order(Integer.MIN_VALUE) // 设置过滤器的权重,越小越先执行。
@Configuration
public class MyGlobalFilterConfig implements GlobalFilter {
/**
* 过滤逻辑和之前的一样,有一些使用不太一样
* @param exchange 请求上下文,可以从里面拿到request和response
* @param chain 放行(和servlet的filter放行一样)
* @return
*/
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// request
ServerHttpRequest request = exchange.getRequest();
// response
ServerHttpResponse response = exchange.getResponse();
/**
* 模拟请求中存在token才放行
*/
// 从request获取携带的数据信息
HttpHeaders headers = request.getHeaders();
// 获取第一个满足的
String token = headers.getFirst("Authorization");
if (token!=null && !token.equals("")){
// 放行 使用chain.filter(exchange),返回类型为Mono
return chain.filter(exchange);
}
// 否则拦截,设置code码 HttpStatus是一个http的枚举类UNAUTHORIZED为401
response.setStatusCode(HttpStatus.UNAUTHORIZED);
return response.setComplete();
}
}
目前一共有三类。
第一类:路由过滤器(GatewayFilter)在哪个路由上设置了,哪个路由才会执行此过滤器
第二类:默认过滤器(DefaultFilter)默认所有的路由(router)都会执行该类过滤器
第三类:全局过滤器(GlobalFilter),和第二类有点类似,但是时需要我们自定义的
设置过滤器的权重:
总结:
1.每个过滤器都可以指定一个int类型的值,表示该过滤器的权重,通过权重的大小来决定执行顺序
2.当多个过滤器的权重值相同的时候,默认的顺序是default先执行,然后是路由过滤器,最后是全局过滤器
小结:上述的三类过滤器的基本使用都差不多了,对于不同过滤器工厂可以参考官网的示例。对于过滤器的使用就差不多这样了
需要注意的是默认过滤器和路由过滤器都是可以通过自定义配置的形式来实现的
查看官方示例
使用元数据为每个路由配置其他参数,如下所示:
spring:
cloud:
gateway:
routes:
- id: route_with_metadata
uri: https://example.org
# matedata 配置元数据
metadata:
optionName: "OptionValue"
compositeObject:
name: "value"
iAmNumber: 1
获取元数据(从请求的上下文中):
Route route = exchange.getAttribute(GATEWAY_ROUTE_ATTR);
// get all metadata properties 获取全部元数据
route.getMetadata();
// get a single metadata property 根据指定的key获取元数据
route.getMetadata(someKey);
测试通过
可以为所有路由配置 http 超时(响应和连接),并为每个特定路由覆盖。
response-timeout: 响应超时配置
connect-timeout: 连接超时配置
配置全局 http 超时:
连接必须以毫秒为单位指定。
如:
spring:
cloud:
gateway:
httpclient:
connect-timeout: 1000
response-timeout: 5s
配置每个路由超时:
连接和响应都必须以毫秒为单位指定。
配置在元数据下
metadata:
optionName: "OptionValue"
compositeObject:
name: "value"
iAmNumber: 1
connect-timeout: 10000
response-timeout:
跨域:一个请求url的协议、域名、端口三者之间任意一个与当前页面url不同即为跨域。
例如:在本机上,前端项目是localhost:8000,后端是8080,那么在前端发起请求到后端的就属于跨域。
产生跨域问题的原因: 出于浏览器的同源策略限制。同源策略是一个重要的安全策略,它用于限制一个origin的文档或者它加载的脚本如何能与另一个源的资源进行交互。它能帮助阻隔恶意文档,减少可能被攻击的媒介。
CORS解决跨域的原理: 在请求的时候会发请求询问后端的服务是否允许跨域,请求类型为options。
因此可以分析需要配置哪些信息:
首先我们是因为前端的请求发送到后端跨域了,所以要配置允许前端的进行跨域,然后会有各种各样的请求如post、get等等请求类型,可以设置我们后端有的请求类型(方法),以及对于这次允许跨域可以管多长时间,毕竟每次都去询问能不能跨域会消耗性能,同时当你允许跨域之后也需要把请求头、cookie信息允许跨域 。
需要配置的信息:
1.允许跨域的信息
2.允许跨域的方法
3.单次设置的跨域可以管多久
4.设置携带的请求头
5.设置是否可以携带请求的cookie
因此,大体的配置就如下图(模板)