Gateway网关

文章目录

Gateway网关1. 网关基本简介1.1 什么是网关1.2 为什么需要网关?

2. 快速搭建gateway网关2.1 创建新模块2.2 引入依赖2.3 编写启动类2.4 配置路由规则2.5 测试

3. 路由过滤4. 过滤器4.1 简介4.2 网关过滤器4.2.2 种类

4.3 自定义过滤器4.3.1 自定义GatewayFilter4.3.2 自定义GlobalFilter

4.4 跨域问题4.4.1 什么是跨域问题4.4.2 解决跨域问题

5. 总结

1. 网关基本简介

1.1 什么是网关

网关,简而言之,是一个系统的单一入口点,它接收所有外部请求,并根据请求的特性(如路径、HTTP方法等)将其转发给内部的各个微服务。

比如说,你想要向一个小区内的一个朋友送信,必须要经过看门大爷的同意,大爷如果认为好人,就会把信带给你要送的人;如果大爷认为你是坏人,就会拦截你。

1.2 为什么需要网关?

路由:微服务架构通常由多个服务组成,每个服务可能部署在不同的地址和端口上。网关可以根据请求的URL或其他条件,将外部请求路由到正确的服务实例上,从而隐藏了服务实例的具体位置。负载均衡:当服务有多个实例时,网关可以根据不同的负载均衡策略(如轮询、随机、最少连接等)将请求分发到不同的实例,确保系统资源的有效利用和服务的稳定性。统一鉴权和认证:在微服务架构中,每个服务都可能有自己的安全要求。网关可以作为统一的鉴权和认证点,处理所有服务的安全验证,简化了服务之间的安全通信。跨域处理:由于浏览器的同源策略,前端应用在访问不同域名或端口的后端服务时可能会遇到跨域问题。网关可以配置CORS(跨源资源共享)策略,允许前端应用安全地访问后端服务。熔断和限流:网关可以集成熔断和限流机制,当后端服务出现问题时,网关可以快速失败,防止级联故障。同时,限流可以控制对后端服务的请求速率,防止服务过载。监控和日志:网关是所有外部请求的入口点,可以在这一层收集和记录重要的监控数据和日志信息,帮助开发者和运维人员快速定位问题和性能瓶颈。

2. 快速搭建gateway网关

基本步骤:

创建新模块引入网关依赖编写启动类配置路由规则

2.1 创建新模块

创建一个新模块gatewawy:

2.2 引入依赖

org.springframework.cloud

spring-cloud-starter-gateway

com.alibaba.cloud

spring-cloud-starter-alibaba-nacos-discovery

org.springframework.cloud

spring-cloud-starter-loadbalancer

2.3 编写启动类

@SpringBootApplication

public class GatewayApplication {

public static void main(String[] args) {

SpringApplication.run(GatewayApplication.class, args);

}

}

2.4 配置路由规则

gateway模块:

server:

port: 8080

spring:

application:

name: gateway-service # 服务名称

cloud:

nacos:

server-addr: 192.168.56.101:8848 # Nacos服务注册中心的地址和端口

gateway:

routes:

- id: user # 路由的唯一标识符,自定义,需要保证唯一性

uri: lb://user-service # 路由的目标服务地址,lb表示使用负载均衡,user-service是注册中心中的服务名

predicates: # 路由断言,用来判断请求是否符合路由规则

- Path=/users/**,/addresses/** # 路由断言的路径模式,匹配以/users/或/addresses/开头的请求路径

解析: 在routes部分,定义了一条路由规则,该规则将所有符合指定路径模式的请求路由到user-service服务。这条规则使用了路径断言Path,匹配所有以/users/或/addresses/开头的请求。通过使用负载均衡lb://前缀,网关能够根据注册中心中的服务实例信息进行负载均衡。

user-service模块:

server:

port: 8084

spring:

application:

name: user-service

cloud:

nacos:

server-addr: 192.168.56.101:8848

2.5 测试

测试接口:

@ApiOperation("网关测试接口")

@GetMapping("/gateway-test")

public String testGateway(){

return "网关测试成功";

}

nacos:

测试:

3. 路由过滤

在前面的gateway的routes部分有四个属性可以配置:

id:路由的唯一标示predicates:路由断言,其实就是匹配条件filters:路由过滤条件uri:路由目标地址,lb://代表负载均衡,从注册中心获取目标微服务的实例列表,并且负载均衡选择一个访问。

我们在配置文件中写的断言规则只是字符串,这些字符串会被 Predicate Factory(断言工厂) 读取并处理,转变为路由判断的条件。例如 Path=/user/** 是按照路径匹配,这个规则是由org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory 类来处理的,这里重点关注路由断言predicates:

名称说明示例After是某个时间点后的请求- After=2037-01-20T17:42:47.789-07:00[America/Denver]Before是某个时间点之前的请求- Before=2031-04-13T15:14:47.433+08:00[Asia/Shanghai]Between是某两个时间点之前的请求- Between=2037-01-20T17:42:47.789-07:00[America/Denver], 2037-01-21T17:42:47.789-07:00[America/Denver]Cookie请求必须包含某些cookie- Cookie=chocolate, ch.pHeader请求必须包含某些header- Header=X-Request-Id, \d+Host请求必须是访问某个host(域名)- Host=**.somehost.org,**.anotherhost.orgMethod请求方式必须是指定方式- Method=GET,POSTPath请求路径必须符合指定规则- Path=/red/{segment},/blue/**Query请求参数必须包含指定参数- Query=name, Jack或者- Query=nameRemoteAddr请求者的ip必须是指定范围- RemoteAddr=192.168.1.1/24weight权重处理

4. 过滤器

4.1 简介

过滤器是用于修改进入网关的请求和发出网关的响应的组件。过滤器的作用范围可以是特定的路由,也可以是全局的。过滤器可以用来添加或修改请求头和响应头,修改请求体,进行权限校验,限流,熔断等。

4.2 网关过滤器

单体架构时我们只需要完成一次用户登录、身份校验,就可以在所有业务中获取到用户信息。而微服务拆分后,每个微服务都独立部署,不再共享数据。也就意味着每个微服务都需要做登录校验,这显然不可取。

而登录校验必须在请求转发到微服务之前做,否则就失去了意义。网关的请求转发是Gateway内部代码实现的,要想在请求转发之前做登录校验,就必须了解Gateway内部工作的基本原理。

如图所示:

客户端请求进入网关后由HandlerMapping对请求做判断,找到与当前请求匹配的路由规则(Route),然后将请求交给WebHandler去处理。WebHandler则会加载当前路由下需要执行的过滤器链(Filter chain),然后按照顺序逐一执行过滤器(后面称为**Filter**)。图中Filter被虚线分为左右两部分,是因为Filter内部的逻辑分为pre和post两部分,分别会在请求路由到微服务之前和之后被执行。只有所有Filter的pre逻辑都依次顺序执行通过后,请求才会被路由到微服务。微服务返回结果后,再倒序执行Filter的post逻辑。最终把响应结果返回。

观察得知:如果我们能够定义一个过滤器,在其中实现登录校验逻辑,并且将过滤器执行顺序定义到NettyRoutingFilter之前,就能解决前面的问题。

4.2.2 种类

网关过滤器链中的过滤器有两种:

GatewayFilter:路由过滤器,作用范围比较灵活,可以是任意指定的路由Route.GlobalFilter:全局过滤器,作用范围是所有路由,不可配置。

下面是一些常用的Gateway Filter和Global Filter:

AddRequestHeader:添加请求头。AddResponseHeader:添加响应头。RewritePath:重写请求路径。PrefixPath:为请求路径添加前缀。SetPath:设置请求路径。Retry:设置重试逻辑。CircuitBreaker:集成熔断器。RequestRateLimiter:限流过滤器。SecureHeaders:添加安全相关的响应头。TokenRelay:用于将认证信息传递给下游服务。

Gateway中内置了很多的GatewayFilter,详情使用可以参考官方文档:

Spring Cloud Gateway

例如AddRequestHeaderGatewayFilterFacotry,顾明思议,就是添加请求头的过滤器,可以给请求添加一个请求头并传递到下游微服务。

使用的使用只需要在application.yaml中这样配置:

spring:

cloud:

gateway:

routes:

- id: user

uri: lb://user-service

predicates:

-Path=/users/**

filters:

- AddRequestHeader=key, value # 逗号之前是请求头的key,逗号之后是value

如果想要让过滤器作用于所有的路由,则可以这样配置:

spring:

cloud:

gateway:

default-filters: # default-filters下的过滤器可以作用于所有路由

- AddRequestHeader=key, value

routes:

- id: user

uri: lb://user-service

predicates:

-Path=/users/**

4.3 自定义过滤器

4.3.1 自定义GatewayFilter

编写过滤器工厂GatewayFilterFactory类

自定义GatewayFilter不是直接实现GatewayFilter,而是实现AbstractGatewayFilterFactory。最简单的方式是这样的:

@Component

public class PrintAnyGatewayFilterFactory extends AbstractGatewayFilterFactory {

@Override

public GatewayFilter apply(Object config) {

return new GatewayFilter() {

@Override

public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {

// 获取请求

ServerHttpRequest request = exchange.getRequest();

// 编写过滤器逻辑

System.out.println("过滤器执行了");

// 放行

return chain.filter(exchange);

}

};

}

}

注意:该类的名称一定要以GatewayFilterFactory为后缀!!!

因为在Spring框架中,很多自动配置功能都是基于约定大于配置的原则,比如命名约定。在这里,如果你实现AbstractGatewayFilterFactory来编写类并以GatewayFilterFactory为后缀命名类的话,Spring Cloud Gateway会自动扫描并识别出那些以GatewayFilterFactory为后缀的Bean然后自动注册加载,不再需要手动配置和加载,大大简化了开发者的配置工作。如果不按照命名约定命名的话多了一步手动配置和加载。

配置路由规则

spring:

cloud:

gateway:

default-filters:

- PrintAny # 此处直接以自定义的GatewayFilterFactory类名称前缀类声明过滤器

另外,这种过滤器还可以支持动态配置参数,不过实现起来比较复杂,示例:

编写过滤器工厂GatewayFilterFactory类

@Component

public class PrintAnyGatewayFilterFactory // 父类泛型是内部类的Config类型

extends AbstractGatewayFilterFactory {

@Override

public GatewayFilter apply(Config config) {

// OrderedGatewayFilter是GatewayFilter的子类,包含两个参数:

// - GatewayFilter:过滤器

// - int order值:值越小,过滤器执行优先级越高

return new OrderedGatewayFilter(new GatewayFilter() {

@Override

public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {

// 获取config值

String a = config.getA();

String b = config.getB();

String c = config.getC();

// 编写过滤器逻辑

System.out.println("a = " + a);

System.out.println("b = " + b);

System.out.println("c = " + c);

// 放行

return chain.filter(exchange);

}

}, 100);

}

// 自定义配置属性,成员变量名称很重要,下面会用到

@Data

static class Config{

private String a;

private String b;

private String c;

}

// 将变量名称依次返回,顺序很重要,将来读取参数时需要按顺序获取

@Override

public List shortcutFieldOrder() {

return List.of("a", "b", "c");

}

// 返回当前配置类的类型,也就是内部的Config

@Override

public Class getConfigClass() {

return Config.class;

}

}

配置路由规则

spring:

cloud:

gateway:

default-filters:

- name: PrintAny # 自定义过滤器的名称

args: # 过滤器传递的参数,手动指定参数名,无需按照参数顺序

a: 1

b: 2

c: 3

4.3.2 自定义GlobalFilter

自定义GlobalFilter则简单很多,直接实现GlobalFilter即可,而且也无法设置动态参数:

@Component

public class PrintAnyGlobalFilter implements GlobalFilter, Ordered {

@Override

public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {

// 编写过滤器逻辑

System.out.println("未登录,无法访问");

// 放行

// return chain.filter(exchange);

// 拦截

ServerHttpResponse response = exchange.getResponse();

response.setRawStatusCode(401);

return response.setComplete();

}

@Override

public int getOrder() {

// 过滤器执行顺序,值越小,优先级越高

return 0;

}

}

4.4 跨域问题

4.4.1 什么是跨域问题

跨域问题(Cross-Origin Resource Sharing, CORS)是指由于浏览器的同源策略(Same-Origin Policy)限制,一个源(域名、协议和端口)的网页无法向另一个源发送HTTP请求的问题。同源策略是一种安全机制,旨在防止恶意网站访问敏感数据。

同源的定义是:如果两个页面的协议、域名(或IP地址)和端口都相同,则它们具有相同的源。例如,以下两个URL具有相同的源:

http://example.com:80/index.htmlhttp://example.com:80/page.html

而以下URL与上面的URL不同源:

https://example.com:80/index.html (协议不同)http://www.example.com:80/index.html (域名不同)http://example.com:81/index.html (端口不同)

当尝试从不同源的客户端发送请求到服务器时,浏览器会阻止这些请求,除非服务器明确允许跨源请求。这就是所谓的跨域问题。

4.4.2 解决跨域问题

全局CORS配置:在网关的配置文件中,可以定义全局的CORS配置,这些配置会应用到所有的路由上。

spring:

application:

name: gateway

cloud:

nacos:

server-addr: 192.168.56.101:8848

gateway:

globalcors:

add-to-simple-url-handler-mapping: true # 因为ajax发起者会通过options请求来向服务器询问是否允许跨域,所以需要设置为true来解决options请求被拦截问题

corsConfigurations:

'[/**]':

allowedOrigins: "http://www.xxx.com" # 允许那些网站跨域访问

allowedMethods: # 允许的HTTP方法

- GET

- POST

- PUT

- DELETE

allowedHeaders: "*" # 允许的请求头

allowCredentials: true # 是否允许发送Cookie

maxAge: 3600 # 预检请求的缓存时间(秒)

5. 总结

本文深入探讨了Spring Cloud Gateway网关的核心概念及其在微服务架构中的快速部署方法,除此之外着重讲解了Gateway过滤器(Filters)的重要性以及相关使用,包括过滤器的种类、自定义过滤器的实现以及过滤器在解决跨域问题中的作用。

至于具体的应用要根据实际开发要求编写,这里就不过多展示了,希望对大家有所帮助。

参考资料:

Gateway网关 - wenxuehai - 博客园 (cnblogs.com)

gateway Strict-origin-when-cross-origin跨域问题解决 | 少将全栈 (whatled.com)

微服务02

精彩内容

评论可见,请评论后查看内容,谢谢!!!评论后请刷新页面。

发表评论

返回顶部暗黑模式