面试常问系列之Gateway网关
API 网关的定义网关的角色是作为一个 API 架构,用来保护、增强和控制对于 API 服务的访问。API 网关是一个处于应用程序或服务(提供 REST API 接口服务)之前的系统,用来管理授权、访问控制和流量限制等,这样 REST API 接口服务就被 API 网关保护起来,对所有的调用者透明。因此,隐藏在 API 网关后面的业务系统就可以专注于创建和管理服务,而不用去处理这些策略性的基础设施
API 网关的定义
网关的角色是作为一个 API 架构,用来保护、增强和控制对于 API 服务的访问。
API 网关是一个处于应用程序或服务(提供 REST API 接口服务)之前的系统,用来管理授权、访问控制和流量限制等,这样 REST API 接口服务就被 API 网关保护起来,对所有的调用者透明。因此,隐藏在 API 网关后面的业务系统就可以专注于创建和管理服务,而不用去处理这些策略性的基础设施。
API 网关的职能
- 请求接入:作为所有API接口服务请求的接入点
- 业务聚合:作为所有后端业务服务的聚合点
- 中介策略:实现安全、验证、路由、过滤、流控等策略
- 统一管理:对所有API服务和策略进行统一管理
使用Gateway的优势
Spring Cloud Gateway 可以看做是一个 Zuul 1.x 的升级版和代替品,比 Zuul 2 更早的使用 Netty 实现异步 IO,从而实现了一个简单、比 Zuul 1.x 更高效的、与 Spring Cloud 紧密配合的 API 网关。
Spring Cloud Gateway 里明确的区分了 Router 和 Filter,并且一个很大的特点是内置了非常多的开箱即用功能,并且都可以通过 SpringBoot 配置或者手工编码链式调用来使用。
比如内置了 10 种 Router,使得我们可以直接配置一下就可以随心所欲的根据 Header、或者 Path、或者 Host、或者 Query 来做路由。
比如区分了一般的 Filter 和全局 Filter,内置了 20 种 Filter 和 9 种全局 Filter,也都可以直接用。当然自定义 Filter 也非常方便。
Gateway的使用
调用流程分析
注意事项:
Predicate(断言)要先于Filter调用,断言为真才能进行路由匹配,而Filter过滤器又分为两种,局部过滤器Gateway Filter和全局过滤器Global Filter.在全局过滤器中可以设置全局过滤器的优先级别,所以两者的调用顺序是由设置的优先级别决定的.
配置格式:
spring:
cloud:
gateway:
routes:
- id: route01 #路由id,自己指定一个唯一值即可
uri: lb://sca-provider #用于获取指定服务名的服务列表
predicates: #断言(谓词):定义请求规则
#断言内容
filters: #网关过滤器,用于对谓词中的内容进行判断分析以及处理
#过滤器内容
几个重要概念
Route(路由):
这是网关的基本构建块.它由一个id,一个目标uri,一组断言和一组过滤器定义.如果断言为真,则路由匹配.
Predicate(断言):
输入类型是一个ServerwebExchange.我们可以使用它来匹配来自HTTP请求的任何内容,例如headers或参数.说白了Predicate就是事先定义了一组匹配规则,方便让请求过来找到对应的 Route 进行处理.
过滤器(filter):
Gateway中的Filter分为两种类型,分别是Gateway Filter和Global Filter.过滤器Filter将会对请求和响应进行修改处理.
综合使用进行匹配
添加测试方法
@GetMapping("/provider/name")
public String name(String name){
return "my name is "+name;
}
创建配置文件
server:
port: 9000
spring:
application:
name: sca-gateway
cloud:
nacos:
discovery:
server-addr: localhost:8848
gateway:
routes: #配置网关路由规则
- id: route01 #路由id,自己指定一个唯一值即可
#uri: http://localhost:8082/ #网关帮我们转发的url
uri: lb://sca-provider #用于获取指定服务名的服务列表
predicates: #断言(谓词):定义请求规则
#- Path=/nacos/provider/echo/** #请求路径定义,此路径对应uri中的资源,多层目录
- Path=/nacos/provider/name
- After=2021-08-23T15:00:00.545+08:00[Asia/Shanghai]
- Header=X-Request-Id, \d+ #添加请求头信息
- Query=pageSize,\d+ #添加请求参数信息
filters: #网关过滤器,用于对谓词中的内容进行判断分析以及处理
- StripPrefix=1 #转发之前去掉path中的第一层路径,例如nacos
- AddRequestParameter=name,zzll #自动添加请求参数
- AddRequestHeader=X-Request-Foo,Bar #自动添加请求头
discovery:
locator:
enabled: true #开启基于服务名获取服务实例的功能(基于服务名创建路由)
#配置白名单
white:
prefix: /nacos #path路径以nacos开头的才能进行下一步操作(白名单)
创建全局过滤器
package com.jt.config;
import com.google.gson.Gson;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import java.util.HashMap;
import java.util.Map;
@Component//交给spring管理
public class AuthGatewayFilter implements GlobalFilter, Ordered {
/**
* @param exchange 基于此对象可以获取请求和响应对象
* @param chain 这个对象指向了一个过滤链(这个链中有多个过滤器)
* @return
*/
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
//1.获取请求对象
ServerHttpRequest request = exchange.getRequest();
//2.获取请求数据
String path = request.getURI().getPath();
System.out.println(path);
String username = request.getQueryParams().getFirst("username");
System.out.println("pageSize="+request.getQueryParams().getFirst("pageSize"));
//3.对请求数据进行处理
System.out.println("whitePrefix="+whitePrefix);
if (!path.startsWith(whitePrefix)){//判断path路径是否以nacos开头,不是则返回一个JSON串
ServerHttpResponse response = exchange.getResponse();
response.setStatusCode(HttpStatus.BAD_GATEWAY);
Map<String,Object> map = new HashMap<String, Object>();
map.put("message", "request failure");
map.put("status", 502);
Gson gson = new Gson();//需先添加gson依赖
String jsonStr = gson.toJson(map);//将map对象转为JSON字符串
byte[] bytes = jsonStr.getBytes();
DataBuffer dataBuffer=response.bufferFactory().wrap(bytes);
return response.writeWith(Mono.just(dataBuffer));
}
//4.返回响应结果
return chain.filter(exchange);
}
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE;//设置全局过滤器的优先级别为最高级,则先经过全局过滤器
}
@Value("${white.prefix}")//获取配置文件中的白名单
private String whitePrefix;
}
使用postman进行测试
成功案例:
失败案例:
如果将path路径的nacos改为其它,如sentinel,即
- Path=/sentinel/provider/name
重新启动后再次测试:
更多推荐
所有评论(0)