所谓的 API 网关,就是指系统的统一入口,它封装了应用程序的内部结构,为客户端提供统一服 务,一些与业务本身功能无关的公共逻辑可以在这里实现,诸如认证、鉴权、监控(黑白名单)、路 由转发等等。
1.
创建一个 api-gateway 的工程并加入依赖
2.
创建启动类
3.书写application.yml配置
4.
启动项目
,
并通过网关去访问微服务
5.
增强版网关
现在在配置文件中写死了转发路径的地址, 前面我们已经分析过地址写死带来的问题, 接下来我
们从注册中心获取此地址。
1)加入
nacos
依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
2)在主启动类上加入服务发现的注解 ----
@EnableDiscoveryClient
3)修改 application.yml 的配置文件
6.
简写版网关
1)
去掉关于路由的配置,修改配置为
2)
启动项目,并通过网关去访问微服务
按照网关地址/微服务/接口的格式去访问,就可以得到成功响应
7.Gateway 核心架构
1)基本概念
路由(Route) 是 gateway 中最基本的组件之一,表示一个具体的路由信息载体。主要定义了下面
的几个信息:
id:是路由标识符,区别于其他 Route。
uri:是路由指向的目的地 uri,即客户端请求最终被转发到的微服务。
order:是用于多个 Route 之间的排序,数值越小排序越靠前,匹配优先级越高。
predicate:是断言的作用是进行条件判断,只有断言都返回真,才会真正的执行路由。
filter:是过滤器用于修改请求和响应信息。
2)
执行流程
8.断言
Predicate(断言,
谓词) 用于进行条件判断,只有断言都返回真,才会真正的执行路由。
断言就是说: 在什么条件下,才能进行路由转发。
基于 Datetime 类型的断言工厂
此类型的断言根据时间做判断,主要有三个:
AfterRoutePredicateFactory: 接收一个日期参数,判断请求日期是否晚于指定日期
BeforeRoutePredicateFactory: 接收一个日期参数,判断请求日期是否早于指定日期
BetweenRoutePredicateFactory: 接收两个日期参数,判断请求日期是否在指定时间段内
- After=2019-12-31T23:59:59.789+08:00[Asia/Shanghai]
基于远程地址的断言工厂 RemoteAddrRoutePredicateFactory:
接收一个 IP 地址段,判断请求主机地址是否在地址段中
- RemoteAddr=192.168.1.1/24
基于 Cookie 的断言工厂
CookieRoutePredicateFactory:接收两个参数,
cookie 名字和一个正则表达式。 判断请求
cookie 是否具有给定名称且值与正则表达式匹配。
- Cookie=chocolate, ch.
基于 Header 的断言工厂
HeaderRoutePredicateFactory:接收两个参数,标题名称和正则表达式。 判断请求
Header 是否
具有给定名称且值与正则表达式匹配。 key value
- Header=X-Request-Id, \d+
基于 Host
的断言工厂
HostRoutePredicateFactory:接收一个参数,主机名模式。判断请求的 Host 是否满足匹配规则。
- Host=**.testhost.org
基于 Method 请求方法的断言工厂
MethodRoutePredicateFactory:接收一个参数,判断请求类型是否跟指定的类型匹配。
- Method=GET
基于 Path 请求路径的断言工厂
PathRoutePredicateFactory:接收一个参数,判断请求的
URI 部分是否满足路径规则。
- Path=/foo/{segment}
基于
Query 请求参数的断言工厂
QueryRoutePredicateFactory :接收两个参数,请求
param 和正则表达式, 判断请求参数是否具有给定名称且值与正则表达式匹配。
- Query=baz, ba.
基于路由权重的断言工厂
WeightRoutePredicateFactory:接收一个[组名
,
权重], 然后对于同一个组内的路由按照权重转发
routes:
- id: weight_route1 uri: host1 predicates:
- Path=/product/**
- Weight=group3, 1
- id: weight_route2 uri: host2 predicates:
- Path=/product/**
- Weight= group3, 9
验证断言:
8.
自定义路由断言工厂
1)在配置文件中,添加一个 Age 的断言配置
2)自定义一个断言工厂, 实现断言方法
package com.yjq.apigateway.predicate;
import org.springframework.cloud.gateway.handler.predicate.AbstractRoutePredicateFactory;
import org.springframework.cloud.gateway.handler.predicate.GatewayPredicate;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.server.ServerWebExchange;
import javax.validation.constraints.NotNull;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
//泛型为自定义的一个配置类,该配置类用来存放配置文件中的值
@Component
public class AgeRoutePredicateFactory extends AbstractRoutePredicateFactory<AgeRoutePredicateFactory.Config> {
public AgeRoutePredicateFactory() {
super(Config.class);
}
public List<String> shortcutFieldOrder() {
return Arrays.asList("minAge", "maxAge");
}
public Predicate<ServerWebExchange> apply(Config config) {
return new GatewayPredicate() {
public boolean test(ServerWebExchange serverWebExchange) {
ServerHttpRequest request = serverWebExchange.getRequest();
String age = request.getQueryParams().getFirst("age");
if (StringUtils.isEmpty(age)){
return false;
}else {
Integer a=Integer.parseInt(age);
if (a>=config.getMinAge()&&a<=config.getMaxAge()){
return true;
}else {
return false;
}
}
}
};
}
@Validated
public static class Config {
@NotNull
private Integer minAge;
@NotNull
private Integer maxAge;
public Integer getMinAge() {
return minAge;
}
public void setMinAge(Integer minAge) {
this.minAge = minAge;
}
public Integer getMaxAge() {
return maxAge;
}
public void setMaxAge(Integer maxAge) {
this.maxAge = maxAge;
}
}
}
3)启动测试
9.过滤器
三个知识点
:
1
作用
:
过滤器就是在请求的传递过程中
,
对请求和响应做一些手脚
2
生命周期: Pre Post (在
Gateway
中
, Filter
的生命周期只有两个:
“pre”
和
“post”
)
PRE
: 这种过滤器在请求被路由之前调用。我们可利用这种过滤器实现身份验证、在集群中选
择请求的微服务、记录调试信息等。
POST
:这种过滤器在路由到微服务以后执行。这种过滤器可用来为响应添加标准的
HTTP
Header
、收集统计信息和指标、将响应从微服务发送给客户端等。
3
分类
:
局部过滤器
(
作用在某一个路由上
)
全局过滤器
(
作用全部路由上
)
1)
局部过滤器---内置局部过滤器
在配置文件中
,
添加
过滤器配置
测试:
截取
修改状态:
2)全局过滤器----自定义全局过滤器
全局过滤器作用于所有路由
,
无需配置。通过全局过滤器可以实现对权限的统一校验,安全性验证等功能。
自定义一个
GlobalFilter
,去校验所有请求的请求参数中是否包含
“token”
,如何不包含请求参数“token”
则不转发路由,否则执行正常的逻辑
自定义全局过滤器的要求:必须实现 GlobalFilter,Order 接口:
package com.yjq.apigateway.filter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
@Component
public class LoginFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request= exchange.getRequest();
String token=request.getHeaders().getFirst("token");
if (!StringUtils.isEmpty(token)){
if ("admin".equals(token)){
return chain.filter(exchange);
}
}
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse().setComplete();
}
// 优先级 值越小优先级越高
@Override
public int getOrder() {
return 0;
}
}
使用postman测试: