Gateway网关
什么是 API 网关(API Gateway)
分布式服务架构、微服务架构与 API 网关
在微服务架构里,服务的粒度被进一步细分,各个业务服务可以被独立的设计、开发、测试、部署和管理。这时,各个独立部署单元可以用不同的开发测试团队维护,可以使用不同的编程语言和技术平台进行设计,这就要求必须使用一种语言和平 台无关的服务协议作为各个单元间的通讯方式。

API 网关的定义
网关的角色是作为一个 API 架构,用来保护、增强和控制对于 API 服务的访问。
API 网关是一个处于应用程序或服务(提供 REST API 接口服务)之前的系统,用来管理授权、访问控制和流量限制等,这样 REST API 接口服务就被 API 网关保护起来,对所有的调用者透明。因此,隐藏在 API 网关后面的业务系统就可以专注于创建和管理服务,而不用去处理这些策略性的基础设施。
API 网关的职能

API 网关的分类与功能

Gateway是什么
Spring Cloud Gateway是Spring官方基于Spring 5.0,Spring Boot 2.0和Project Reactor等技术开发的网关,Spring Cloud Gateway旨在为微服务架构提供一种简单而有效的统一的API路由管理方式。Spring Cloud Gateway作为Spring Cloud生态系中的网关,目标是替代ZUUL,其不仅提供统一的路由方式,并且基于Filter链的方式提供了网关基本的功能,例如:安全,监控/埋点,和限流等。
功能

helloworld
创建
gateway项目
引入依赖
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
</dependencies>编写启动类
package com.lazy.gateway;
public class MainApplication {
public static void main(String[] args) {
SpringApplication.run(MainApplication.class, args);
}
}配置文件
spring:
application:
name: gateway
cloud:
nacos:
server-addr: localhost:8848
server:
port: 80
配置网关
新建application-route.yaml
spring: |
application.yaml
spring: |
service-order
package com.lazy.cloud.controller; |
package com.lazy.cloud.feign; |
service-product
package com.lazy.cloud.controller; |
运行测试一下

发现503,因为我们的gateway项目的配置文件添加了,负载均衡,但没有引入负载均衡的依赖,所以显示没有可用服务
我们在gateway项目中引入负载均衡的依赖
<dependency> |
再重启一下试试

刷新了四遍,看看service-order两个服务有没有打印


当我们这个设置,他会访问那个?
spring: |

可以看到,他是首先访问的是必应页面,那我们从中得出,他是按照先后顺序来进行访问的,我们也可以通过order来修改它的顺序,数字越小,优先级越高
spring: |
再重启一下试试

发现它访问的是我们自己写的页面,如果访问别的话,他会跳转到必应页面,因为必应配置的是下面所有请求都可以访问

如果这样写的话,也可以生效
spring: |
效果


Predicate - 断言

Query示例:
spring: |
启动测试

从上图看出,我们访问/search会出现404,当我们带上参数后,且参数值为haha再试试

当我们随便换一个参数值后

自定义断言工厂
我们想要实现一个基于上面的在加上vip指定用户才可以访问,否则不能访问!
编写
VipPredicateFactory类package com.lazy.gateway.predicate;
public class VipPredicateFactory extends VipPredicateFactory<VipRoutePredicateFactory.Config> {
public VipPredicateFactory() {
super(Config.class);
}
public List<String> shortcutFieldOrder() {
return Arrays.asList("param","value");
}
public Predicate<ServerWebExchange> apply(Config config) {
return (GatewayPredicate) serverWebExchange -> {
// 获取 request 请求
ServerHttpRequest request = serverWebExchange.getRequest();
// 获取第一个请求参数
String first = request.getQueryParams().getFirst(config.param);
//判断 param 不为空,并且参数值和配置文件的参数值相等
return StringUtils.hasText(first) && Objects.equals(first, config.value);
};
}
public static class Config {
private String param;
private String value;
public void setParam( String param) {
this.param = param;
}
public String getParam() {
return param;
}
public void setValue( String value) {
this.value = value;
}
public String getValue() {
return value;
}
}
}配置文件
spring:
cloud:
gateway:
routes:
- id: biying
uri: https://cn.bing.com/
predicates:
- name: Path # 路径断言
args:
patterns: /search
- name: Query # 查询断言
args:
param: q # 必须满足参数是q
regexp: haha # 参数值是 haha 才能,跳转到相应的路径
- name: VipPredicateFactory # 这个参数名必须和配置的类名一样
args:
param: user
value: lazy测试

参数部分顺序,必须这两个条件同时满足才会生效!
注意:
如果类名是以
xxxRoutePredicateFactory命名的话,到时候配置文件的name属性可以,xxx写,不需要写完整名,否则就写完整名
过滤器
| 名 | 参数(个数/类型) | 作用 |
|---|---|---|
| AddRequestHeader | 2/string | 添加请求头 |
| AddRequestHeadersIfNotPresent | 1/List<string> | 如果没有则添加请求头,key:value方式 |
| AddRequestParameter | 2/string、string | 添加请求参数 |
| AddResponseHeader | 2/string、string | 添加响应头 |
| CircuitBreaker | 1/string | 仅支持forward:/inCaseOfFailureUseThis方式进行熔断 |
| CacheRequestBody | 1/string | 缓存请求体 |
| DedupeResponseHeader | 1/string | 移除重复响应头,多个用空格分割 |
| FallbackHeaders | 1/string | 设置Fallback头 |
| JsonToGrpc | 请求体Json转为gRPC | |
| LocalResponseCache | 2/string | 响应数据本地缓存 |
| MapRequestHeader | 2/string | 把某个请求头名字变为另一个名字 |
| ModifyRequestBody | 仅 Java 代码方式 | 修改请求体 |
| ModifyResponseBody | 仅 Java 代码方式 | 修改响应体 |
| PrefixPath | 1/string | 自动添加请求前缀路径 |
| PreserveHostHeader | 0 | 保护Host头 |
| RedirectTo | 3/string | 重定向到指定位置 |
| RemoveJsonAttributesResponseBody | 1/string | 移除响应体中的某些Json字段,多个用,分割 |
| RemoveRequestHeader | 1/string | 移除请求头 |
| RemoveRequestParameter | 1/string | 移除请求参数 |
| RemoveResponseHeader | 1/string | 移除响应头 |
| RequestHeaderSize | 2/string | 设置请求大小,超出则响应431状态码 |
| RequestRateLimiter | 1/string | 请求限流 |
| RewriteLocationResponseHeader | 4/string | 重写Location响应头 |
| RewritePath | 2/string | 路径重写 |
| RewriteRequestParameter | 2/string | 请求参数重写 |
| RewriteResponseHeader | 3/string | 响应头重写 |
| SaveSession | 0 | session保存,配合spring-session框架 |
| SecureHeaders | 0 | 安全头设置 |
| SetPath | 1/string | 路径修改 |
| SetRequestHeader | 2/string | 请求头修改 |
| SetResponseHeader | 2/string | 响应头修改 |
| SetStatus | 1/int | 设置响应状态码 |
| StripPrefix | 1/int | 路径层级拆除 |
| Retry | 7/string | 请求重试设置 |
| RequestSize | 1/string | 请求大小限定 |
| SetRequestHostHeader | 1/string | 设置Host请求头 |
| TokenRelay | 1/string | OAuth2的token转发 |
示例:
去除,controller的/api/order和/api/product请求,使用过滤器添加
spring: |
效果:

默认过滤器
添加过滤器并将其应用于所有路由,可以使用 spring.cloud.gateway.default-filters 。该属性接受一个过滤器列表。以下列表定义了一组默认过滤器:
spring: |
测试:
我们访问/api/order/readDb会有响应头和/api/product/product/1也会有响应头


全局过滤器GlobalFilter
我们想记录请求时间和响应时间用了多少毫秒,我们就可以使用GlobalFilter来记录
package com.lazy.gateway.filter; |

自定义过滤器
如果我们想在请求头里面添加token,可以自定义使用过滤器添加,如果写的是uuid我们就生成uuid,如果写的是jwt那我们就生成jwt
package com.lazy.gateway.filter; |
spring: |

注意:
只要文件后缀名为
XXXGatewayFilterFactory,配置文件配置的时候就可以写XXX,可以省略GatewayFilterFactory
Gateway解决跨域请求
由于我们的项目被月拆分越多,我们不可能在每一个项目都配置解决跨域请求,然而spring官网就给我在Gateway网关上统一配置解决方案
spring: |
也可以单独在某一个请求下面配置跨域
spring: |
效果

微服务内部调用是否需要走网关
在微服务架构中,服务网关通常用于处理外部请求的路由转发、权限校验、限流和监控等功能。然而,对于微服务内部的调用,是否需要经过网关,取决于具体的架构设计和需求。
服务网关的作用
服务网关主要用于接收外部请求,并将其转发到后端的微服务上,同时可以在网关中实现一系列的横切功能,如权限校验、限流和监控。通过将这些功能集中在网关中,可以避免在每个微服务中重复实现这些功能,从而减少代码冗余和维护成本。
内部调用是否需要走网关
对于微服务内部的调用,通常不需要经过网关。原因如下:
- 性能考虑:增加网关会增加一层转发,可能会导致性能下降。
- 内部请求的特殊性:内部服务之间的调用通常不需要进行权限校验和限流等操作。
- 网关是直接对接前端的。
例外情况
在某些情况下,可能会选择让内部调用也经过网关,例如:
- 统一监控和日志:如果希望对所有的服务调用进行统一的监控和日志记录,可以选择让内部调用也经过网关。
- 简化架构:在某些复杂的架构中,通过网关可以简化服务间的调用逻辑和管理。


