目录
概念:
三大核心:
工作流程:
9527网关如何做路由映射:
GetWay高级特性:
按服务名动态路由服务:
断言Route Predicate Factories :
获取当前时区时间:
After Route :
例:
Before,Between 同理:
Cookie Route :
Header Route :
自定义断言 :
Filter过滤器:
1. Filter的作用
2. Filter的分类
1. Pre Filter(前置过滤器)
2. Post Filter(后置过滤器)
3. Error Filter(错误过滤器)
例
请求头AddRequestHeader :
请求参数 RemoveRequestParameter和AddRequestParameter
请求回应ResponseHeader:
前缀和路径相关组:
全局过滤器:
自定义条件Filter:
概念:
微服务中网关在哪里?
三大核心:
Route路由 ,Predicate断言,Filter过滤器
工作流程:
核心逻辑:路由转发,断言判断,执行过滤器链
9527网关如何做路由映射:
前提:
我们需要提前把GeteWay服务注册到consul当中
核心:配置yml
server:port: 9527spring:application:name: cloud-gateway #以微服务注册进consul或nacos服务列表内cloud:consul: #配置consul地址host: localhostport: 8500discovery:prefer-ip-address: trueservice-name: ${spring.application.name}gateway:routes:- id: pay_routh1 #pay_routh1 #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名uri: http://localhost:8001 #匹配后提供服务的路由地址predicates:- Path=/pay/gateway/get/** # 断言,路径相匹配的进行路由- id: pay_routh2 #pay_routh2 #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名uri: http://localhost:8001 #匹配后提供服务的路由地址predicates:- Path=/pay/gateway/info/** # 断言,路径相匹配的进行路由
隐真示假 ,让用户不知道我们真正的地址:
没有使用GeteWay之前访问的路径是 http://localhost:8001/pay/gateway/get/1
使用了GeteWay之后可以使用http://localhost:9527/pay/gateway/get/1
将feignclient请求的微服务更改为注册中心的geteway:
先启动 8001微服务和feign80,可以看到请求失败:
启动9527网关后,请求成功,说明现在请求微服务必须通过geteway,配置成功:
GetWay高级特性:
按服务名动态路由服务:
格式:
uri:lb://service
微服务名为cloud-payment-service,通过使用注册中心的微服务名称,就可以动态的配置路由地址,配置如下:
断言Route Predicate Factories :
官网地址:点击跳转
通过断言判断请求是否路由到微服务。
获取当前时区时间:
在讲解之前,我们需要先知道如何获取默认时区时间
public static void main(String[] args) {ZonedDateTime zbj = ZonedDateTime.now(); // 默认时区System.out.println(zbj); }
After Route :
官网描述如下:
表示只有在当前时间之后,该路由才会被匹配。
例:
yml配置格式 ,我配置的时间是大于当前时间的,但我们必须要在该时间后才能访问到:
spring:
cloud:
gateway:
routes:
- id: route1
uri: http://localhost:8081
predicates:
- Path=/api/**
- After=2024-12-26T17:31:14.523838700+08:00[Asia/Shanghai]
访问结果如下:
Before,Between 同理:
Cookie Route :
官方描述如下:
通过键值对的方式配置Cookie,访问时必须带上Cookie,否则访问不到服务。
Header Route :
请求头要有X-Request-Id属性并且值为整数的正则表达式
其他的断言用到了请查阅官方文档,写得很详细
自定义断言 :
java">@Component
public class MyRoutePredicateFactory extends AbstractRoutePredicateFactory<MyRoutePredicateFactory.Config>
{public MyRoutePredicateFactory(){super(MyRoutePredicateFactory.Config.class);}@Validatedpublic static class Config{@Setter@Getter@NotEmptyprivate String userType; //钻、金、银等用户等级}@Overridepublic Predicate<ServerWebExchange> apply(MyRoutePredicateFactory.Config config){return new Predicate<ServerWebExchange>(){@Overridepublic boolean test(ServerWebExchange serverWebExchange){//检查request的参数里面,userType是否为指定的值,符合配置就通过String userType = serverWebExchange.getRequest().getQueryParams().getFirst("userType");if (userType == null) return false;//如果说参数存在,就和config的数据进行比较if(userType.equals(config.getUserType())) {return true;}return false;}};}//开启shortcut支持@Overridepublic List<String> shortcutFieldOrder() {return Collections.singletonList("userType");}
}
YML配置:
必须加上usertype=diamond才能访问的服务
Filter过滤器:
官方文档:点击跳转
1. Filter的作用
Filters 通常用于以下几种场景:
- 请求预处理:对请求进行检查、修改、验证或转换,如请求数据格式化、认证、限流、日志记录等。
- 响应后处理:在响应数据返回客户端之前进行处理,如数据加密、响应格式化、缓存处理等。
- 路由转发:基于请求中的一些特定信息(如URL路径、请求头、请求参数等)决定如何路由请求。
2. Filter的分类
在不同的网关架构中,Filter的分类有所不同。以 Spring Cloud Gateway 和 API Gateway 为例,它们通常将 Filter 分为以下几种类型:
1. Pre Filter(前置过滤器)
前置过滤器在请求到达服务之前执行。它们可以用来进行:
- 身份验证:如检查JWT令牌是否合法。
- 日志记录:记录请求的信息。
- 限流:检查请求是否超过某些限制。
2. Post Filter(后置过滤器)
后置过滤器在服务响应后,客户端接收到响应之前执行。它们可以用来:
- 修改响应:比如修改响应体或响应头。
- 性能监控:计算请求处理时间,进行性能分析。
- 缓存处理:根据某些条件返回缓存的响应。
3. Error Filter(错误过滤器)
错误过滤器用于处理请求过程中发生的错误。例如:
- 统一错误处理:当发生异常时,返回特定的错误响应。
- 日志记录:记录错误信息以便后续分析。
例
请求头AddRequestHeader :
是 Spring Cloud Gateway 中的一个 GatewayFilter 工厂,用于在请求转发之前,向请求中添加自定义的 HTTP 请求头。
向服务端新增方法:
java">@GetMapping(value = "/pay/gateway/filter")public ResultData<String> getGatewayFilter(HttpServletRequest request){String result = "";Enumeration<String> headers = request.getHeaderNames();while(headers.hasMoreElements()){String headName = headers.nextElement();String headValue = request.getHeader(headName);System.out.println("请求头名: " + headName +"\t\t\t"+"请求头值: " + headValue);if(headName.equalsIgnoreCase("X-Request-atguigu1")|| headName.equalsIgnoreCase("X-Request-atguigu2")) {result = result+headName + "\t " + headValue +" ";}}return ResultData.success("getGatewayFilter 过滤器 test: "+result+" \t "+ DateUtil.now());}
yml配置:
- id: pay_routh3 #pay_routh3uri: lb://cloud-payment-service #匹配后提供服务的路由地址predicates:- Path=/pay/gateway/filter/** # 断言,路径相匹配的进行路由filters:- AddRequestHeader=X-Request-atguigu1,atguiguValue1 # 请求头kv,若一头含有多参则重写一行设置- AddRequestHeader=X-Request-atguigu2,atguiguValue2
运行结果:
请求参数 RemoveRequestParameter和
AddRequestParameter
打印输入的参数
java">System.out.println("=============================================");String customerId = request.getParameter("customerId");System.out.println("request Parameter customerId: "+customerId);String customerName = request.getParameter("customerName");System.out.println("request Parameter customerName: "+customerName);System.out.println("=============================================");
yml添加:
- AddRequestParameter=customerId,9527001 # 新增请求参数Parameter:k ,v - RemoveRequestParameter=customerName # 删除url请求参数customerName,你传递过来也是null
测试请求的路径;
http://localhost:9527/pay/gateway/filter?customerId=9999&customerName=z3
打印结果:
可以发现添加到参数会覆盖原有的值,移除的参数就算是传值也会被置为null
请求回应ResponseHeader:
修改之前的响应头:
配置yml:
- AddResponseHeader=X-Response-atguigu, BlueResponse # 新增请求参数X-Response-atguigu并设值为BlueResponse - SetResponseHeader=Date,2099-11-11 # 设置回应头Date值为2099-11-11 - RemoveResponseHeader=Content-Type # 将默认自带Content-Type回应属性删除
修改后响应头:
前缀和路径相关组:
The PrefixPath GatewayFilter Factory
The SetPath GatewayFilter Factory
The RedirectTo GatewayFilter Factory
全局过滤器:
官方文档:点击跳转
新建global类:
java">package com.atguigu.cloud.mygateway;import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;import java.util.Map;@Component
@Slf4j
public class MyGlobalFilter implements GlobalFilter, Ordered {public final static String BEGIN_VISIT_TIME = "beginVisitTime";@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {//记录访问接口开始时间exchange.getAttributes().put(BEGIN_VISIT_TIME, System.currentTimeMillis());//返回统计的各个结果给后台return chain.filter(exchange).then(Mono.fromRunnable(()->{Long beginVisitTime = exchange.getAttribute(BEGIN_VISIT_TIME);if(beginVisitTime != null){log.info("访问接口主机:"+exchange.getRequest().getURI().getHost());log.info("访问接口端口:"+exchange.getRequest().getURI().getPort());log.info("访问接口URL:"+exchange.getRequest().getURI().getPath());log.info("访问接口URL后面的参数:"+exchange.getRequest().getURI().getRawQuery());log.info("访问接口时长:"+(System.currentTimeMillis()-beginVisitTime)+"毫秒");log.info("=================分割线======================");System.out.println();}}));}@Overridepublic int getOrder() {return 0;}
}
yml:
测试结果:
自定义条件Filter:
过滤条件是 必须带有 ’yuanshen‘的请求参数
java">package com.atguigu.cloud.mygateway;import lombok.Getter;
import lombok.Setter;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.cloud.gateway.filter.factory.SetPathGatewayFilterFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;import java.util.Arrays;
import java.util.List;@Component
public class MyGatewayFilterFactory extends AbstractGatewayFilterFactory<MyGatewayFilterFactory.Config>
{public MyGatewayFilterFactory(){super(MyGatewayFilterFactory.Config.class);}@Overridepublic GatewayFilter apply(MyGatewayFilterFactory.Config config){return new GatewayFilter(){@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain){ServerHttpRequest request = exchange.getRequest();System.out.println("进入了自定义网关过滤器MyGatewayFilterFactory,status:"+config.getStatus());if(request.getQueryParams().containsKey("atguigu")){return chain.filter(exchange);}else{exchange.getResponse().setStatusCode(HttpStatus.BAD_REQUEST);return exchange.getResponse().setComplete();}}};}@Overridepublic List<String> shortcutFieldOrder() {return Arrays.asList("status");}public static class Config{@Getter@Setterprivate String status;//设定一个状态值/标志位,它等于多少,匹配和才可以访问}
}
//单一内置过滤器GatewayFilter
yml:
补充:
对应关系: