目录
一、Gateway网关创建
1.1、创建微服务子工程9527及配置和依赖
1.1.1、pom依赖
1.1.2、yml配置
1.1.3、主启动类并测试入驻consul
二、实现路由映射
2.1、服务8001新增测试代码
2.2、修改9527服务yml配置文件
2.3、远程调用接口加gateway
2.3.1、新增80服务测试代码
三、路由以微服务名动态获取服务URL
3.1、修改9527服务yml文件
四、断言
4.1、常用断言api的yml配置
4.1.1、时间范围访问设置
4.1.3、X-Request-Id访问
4.1.4、Host访问
4.1.5、Query访问
4.1.6、RemoteAddr访问
4.1.7、Method访问
4.2、自定义断言
五、过滤器
5.1、常用内置过滤器
5.1.1、请求头添加、修改、删除
5.1.2、请求参数删除和添加
5.1.3、回应头添加、修改、删除
5.1.4、前缀和路径相关
5.2、自定义过滤器
5.2.1、自定义全局过滤器
5.2.2、自定义条件过滤器
一、Gateway网关创建
核心功能:反向代理、鉴权、流量控制、熔断、监控日志
三大核心:路由(route)、断言(predicate)、过滤(filter)
工作流程核心逻辑:路由转发-》断言判断-》执行过滤链
1.1、创建微服务子工程9527及配置和依赖
1.1.1、pom依赖
<dependencies><!--gateway--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId></dependency><!--服务注册发现consul discovery,网关也要注册进服务注册中心统一管控--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-consul-discovery</artifactId></dependency><!-- 指标监控健康检查的actuator,网关是响应式编程删除掉spring-boot-starter-web dependency--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build>
1.1.2、yml配置
server:port: 9527spring:application:name: cloud-gateway #以微服务注册进consul或nacos服务列表内cloud:consul: #配置consul地址host: localhostport: 8500discovery:prefer-ip-address: trueservice-name: ${spring.application.name}
1.1.3、主启动类并测试入驻consul
@SpringBootApplication
@EnableDiscoveryClient
public class Main9527 {public static void main(String[] args) {SpringApplication.run(Main9527.class,args);}
}
二、实现路由映射
2.1、服务8001新增测试代码
@RestController
public class PayGateWayController {@Resourceprivate PayService payService;@GetMapping(value = "/pay/gateway/get/{id}")public ResultData<Pay> getById(@PathVariable("id") Integer id){Pay pay = payService.getById(id);return ResultData.success(pay);}@GetMapping(value = "/pay/gateway/info")public ResultData<String> getGatewayInfo(){return ResultData.success("gateway info test:"+ IdUtil.simpleUUID());}
}
2.2、修改9527服务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/** # 断言,路径相匹配的进行路由
结果:
2.3、远程调用接口加gateway
/*** GateWay进行网关测试案例01* @param id* @return*/@GetMapping(value = "/pay/gateway/get/{id}")public ResultData getById(@PathVariable("id") Integer id);/*** GateWay进行网关测试案例02* @return*/@GetMapping(value = "/pay/gateway/info")public ResultData<String> getGatewayInfo();
2.3.1、新增80服务测试代码
@RestController
public class OrderGateWayController {@Resourceprivate PayFeignApi payFeignApi;@GetMapping(value = "/feign/pay/gateway/get/{id}")public ResultData getById(@PathVariable("id") Integer id){return payFeignApi.getById(id);}@GetMapping(value = "/feign/pay/gateway/info")public ResultData<String> getGatewayInfo(){return payFeignApi.getGatewayInfo();}
}
三、路由以微服务名动态获取服务URL
3.1、修改9527服务yml文件
gateway:routes:- id: pay_routh1 #pay_routh1 #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名
# uri: http://localhost:8001 #匹配后提供服务的路由地址uri: lb://cloud-payment-servicepredicates:- Path=/pay/gateway/get/** # 断言,路径相匹配的进行路由- id: pay_routh2 #pay_routh2 #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名
# uri: http://localhost:8001 #匹配后提供服务的路由地址uri: lb://cloud-payment-servicepredicates:- Path=/pay/gateway/info/** # 断言,路径相匹配的进行路由
四、断言
4.1、常用断言api的yml配置
4.1.1、时间范围访问设置
gateway:routes:- id: pay_routh1 #pay_routh1 #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名
# uri: http://localhost:8001 #匹配后提供服务的路由地址uri: lb://cloud-payment-servicepredicates:- Path=/pay/gateway/get/** # 断言,路径相匹配的进行路由
# - After=2024-05-04T23:53:30.106114600+08:00[Asia/Shanghai] #在此时间之后访问
# - Before=2024-05-04T23:56:30.106114600+08:00[Asia/Shanghai] #在此时间之前访问
# - Between=2024-05-04T23:57:30.106114600+08:00[Asia/Shanghai],2024-05-05T00:59:30.106114600+08:00[Asia/Shanghai]
4.1.2、cookie访问
gateway:routes:- id: pay_routh1 #pay_routh1 #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名
# uri: http://localhost:8001 #匹配后提供服务的路由地址uri: lb://cloud-payment-servicepredicates:- Path=/pay/gateway/get/** # 断言,路径相匹配的进行路由
# - After=2024-05-04T23:53:30.106114600+08:00[Asia/Shanghai] #在此时间之后访问
# - Before=2024-05-04T23:56:30.106114600+08:00[Asia/Shanghai] #在此时间之前访问
# - Between=2024-05-04T23:57:30.106114600+08:00[Asia/Shanghai],2024-05-05T00:59:30.106114600+08:00[Asia/Shanghai]
# - Cookie=username,cjc #必须要携带cookie才能访问
测试1:原生命令访问
测试2:使用postman访问
测试3:使用浏览器访问
4.1.3、X-Request-Id访问
gateway:routes:- id: pay_routh1 #pay_routh1 #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名
# uri: http://localhost:8001 #匹配后提供服务的路由地址uri: lb://cloud-payment-servicepredicates:- Path=/pay/gateway/get/** # 断言,路径相匹配的进行路由
# - After=2024-05-04T23:53:30.106114600+08:00[Asia/Shanghai] #在此时间之后访问
# - Before=2024-05-04T23:56:30.106114600+08:00[Asia/Shanghai] #在此时间之前访问
# - Between=2024-05-04T23:57:30.106114600+08:00[Asia/Shanghai],2024-05-05T00:59:30.106114600+08:00[Asia/Shanghai]
# - Cookie=username,cjc #必须要携带cookie才能访问- Header=X-Request-Id, \d+ # 请求头要有X-Request-Id属性并且值为整数
4.1.4、Host访问
gateway:routes:- id: pay_routh1 #pay_routh1 #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名
# uri: http://localhost:8001 #匹配后提供服务的路由地址uri: lb://cloud-payment-servicepredicates:- Path=/pay/gateway/get/** # 断言,路径相匹配的进行路由
# - After=2024-05-04T23:53:30.106114600+08:00[Asia/Shanghai] #在此时间之后访问
# - Before=2024-05-04T23:56:30.106114600+08:00[Asia/Shanghai] #在此时间之前访问
# - Between=2024-05-04T23:57:30.106114600+08:00[Asia/Shanghai],2024-05-05T00:59:30.106114600+08:00[Asia/Shanghai]
# - Cookie=username,cjc #必须要携带cookie才能访问
# - Header=X-Request-Id, \d+ # 请求头要有X-Request-Id属性并且值为整数- Host=**.cjc.com
4.1.5、Query访问
gateway:routes:- id: pay_routh1 #pay_routh1 #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名
# uri: http://localhost:8001 #匹配后提供服务的路由地址uri: lb://cloud-payment-servicepredicates:- Path=/pay/gateway/get/** # 断言,路径相匹配的进行路由
# - After=2024-05-04T23:53:30.106114600+08:00[Asia/Shanghai] #在此时间之后访问
# - Before=2024-05-04T23:56:30.106114600+08:00[Asia/Shanghai] #在此时间之前访问
# - Between=2024-05-04T23:57:30.106114600+08:00[Asia/Shanghai],2024-05-05T00:59:30.106114600+08:00[Asia/Shanghai]
# - Cookie=username,cjc #必须要携带cookie才能访问
# - Header=X-Request-Id, \d+ # 请求头要有X-Request-Id属性并且值为整数
# - Host=**.cjc.com- Query=username, \d+ # 要有参数名username并且值还要是整数才能路由
4.1.6、RemoteAddr访问
gateway:routes:- id: pay_routh1 #pay_routh1 #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名
# uri: http://localhost:8001 #匹配后提供服务的路由地址uri: lb://cloud-payment-servicepredicates:- Path=/pay/gateway/get/** # 断言,路径相匹配的进行路由
# - After=2024-05-04T23:53:30.106114600+08:00[Asia/Shanghai] #在此时间之后访问
# - Before=2024-05-04T23:56:30.106114600+08:00[Asia/Shanghai] #在此时间之前访问
# - Between=2024-05-04T23:57:30.106114600+08:00[Asia/Shanghai],2024-05-05T00:59:30.106114600+08:00[Asia/Shanghai]
# - Cookie=username,cjc #必须要携带cookie才能访问
# - Header=X-Request-Id, \d+ # 请求头要有X-Request-Id属性并且值为整数
# - Host=**.cjc.com
# - Query=username, \d+ # 要有参数名username并且值还要是整数才能路由- RemoteAddr=192.168.200.1/24 # 外部访问我的IP限制,最大跨度不超过32,目前是1~24它们是 CIDR 表示法。
4.1.7、Method访问
gateway:routes:- id: pay_routh1 #pay_routh1 #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名
# uri: http://localhost:8001 #匹配后提供服务的路由地址uri: lb://cloud-payment-servicepredicates:- Path=/pay/gateway/get/** # 断言,路径相匹配的进行路由
# - After=2024-05-04T23:53:30.106114600+08:00[Asia/Shanghai] #在此时间之后访问
# - Before=2024-05-04T23:56:30.106114600+08:00[Asia/Shanghai] #在此时间之前访问
# - Between=2024-05-04T23:57:30.106114600+08:00[Asia/Shanghai],2024-05-05T00:59:30.106114600+08:00[Asia/Shanghai]
# - Cookie=username,cjc #必须要携带cookie才能访问
# - Header=X-Request-Id, \d+ # 请求头要有X-Request-Id属性并且值为整数
# - Host=**.cjc.com
# - Query=username, \d+ # 要有参数名username并且值还要是整数才能路由- RemoteAddr=192.168.200.1/24 # 外部访问我的IP限制,最大跨度不超过32,目前是1~24它们是 CIDR 表示法。- Method=Put
4.2、自定义断言
测试代码
@Component
public class MyRoutePredicateFactory extends AbstractRoutePredicateFactory<MyRoutePredicateFactory.Config> {public MyRoutePredicateFactory(){super(MyRoutePredicateFactory.Config.class);}//断言规则@Validatedpublic static class Config{@Getter@Setter@NotEmptyprivate String userType;}//重写支持短格式@Overridepublic List<String> shortcutFieldOrder() {return Collections.singletonList("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");//如果说参数存在,就和config的数据进行比较if (userType.equalsIgnoreCase(config.getUserType())) {return true;} else if (userType == null) {return false;}return false;}};}
}
配置yml文件
gateway:routes:- id: pay_routh1 #pay_routh1 #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名
# uri: http://localhost:8001 #匹配后提供服务的路由地址uri: lb://cloud-payment-servicepredicates:- Path=/pay/gateway/get/** # 断言,路径相匹配的进行路由
# - After=2024-05-04T23:53:30.106114600+08:00[Asia/Shanghai] #在此时间之后访问
# - Before=2024-05-04T23:56:30.106114600+08:00[Asia/Shanghai] #在此时间之前访问
# - Between=2024-05-04T23:57:30.106114600+08:00[Asia/Shanghai],2024-05-05T00:59:30.106114600+08:00[Asia/Shanghai]
# - Cookie=username,cjc #必须要携带cookie才能访问
# - Header=X-Request-Id, \d+ # 请求头要有X-Request-Id属性并且值为整数
# - Host=**.cjc.com
# - Query=username, \d+ # 要有参数名username并且值还要是整数才能路由
# - RemoteAddr=192.168.200.1/24 # 外部访问我的IP限制,最大跨度不超过32,目前是1~24它们是 CIDR 表示法。
# - Method=Put- My=diamond
# - name: My #全面支持
# args:
# userType: diamond
五、过滤器
5.1、常用内置过滤器
5.1.1、请求头添加、修改、删除
修改9527yml配置文件
gateway:routes:- id: pay_routh1 #pay_routh1 #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名
# uri: http://localhost:8001 #匹配后提供服务的路由地址uri: lb://cloud-payment-servicepredicates:- Path=/pay/gateway/get/** # 断言,路径相匹配的进行路由
# - After=2024-05-04T23:53:30.106114600+08:00[Asia/Shanghai] #在此时间之后访问
# - Before=2024-05-04T23:56:30.106114600+08:00[Asia/Shanghai] #在此时间之前访问
# - Between=2024-05-04T23:57:30.106114600+08:00[Asia/Shanghai],2024-05-05T00:59:30.106114600+08:00[Asia/Shanghai]
# - Cookie=username,cjc #必须要携带cookie才能访问
# - Header=X-Request-Id, \d+ # 请求头要有X-Request-Id属性并且值为整数
# - Host=**.cjc.com
# - Query=username, \d+ # 要有参数名username并且值还要是整数才能路由
# - RemoteAddr=192.168.200.1/24 # 外部访问我的IP限制,最大跨度不超过32,目前是1~24它们是 CIDR 表示法。
# - Method=Put- My=diamond
# - name: My #全面支持
# args:
# userType: diamond- id: pay_routh2 #pay_routh2 #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名
# uri: http://localhost:8001 #匹配后提供服务的路由地址uri: lb://cloud-payment-servicepredicates:- Path=/pay/gateway/info/** # 断言,路径相匹配的进行路由- id: pay_routh3 #pay_routh3uri: lb://cloud-payment-service #匹配后提供服务的路由地址predicates:- Path=/pay/gateway/filter/** # 断言,路径相匹配的进行路由filters:- AddRequestHeader=X-Request-cjc1,cjcValue1 # 请求头kv,若一头含有多参则重写一行设置- AddRequestHeader=X-Request-cjc2,cjcValue2- RemoveRequestHeader=cache-control # 删除请求头cache-control- SetRequestHeader=x-forwarded-host, yyyy # 将请求头x-forwarded-host对应的值修改为yyyy
8001测试代码
@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-cjc1")|| headName.equalsIgnoreCase("X-Request-cjc2")) {result = result+headName + "\t " + headValue +" ";}}return ResultData.success("getGatewayFilter 过滤器 test: "+result+" \t "+ DateUtil.now());}
5.1.2、请求参数删除和添加
- id: pay_routh3 #pay_routh3uri: lb://cloud-payment-service #匹配后提供服务的路由地址predicates:- Path=/pay/gateway/filter/** # 断言,路径相匹配的进行路由filters:- AddRequestHeader=X-Request-cjc1,cjcValue1 # 请求头kv,若一头含有多参则重写一行设置- AddRequestHeader=X-Request-cjc2,cjcValue2- RemoveRequestHeader=cache-control # 删除请求头cache-control- SetRequestHeader=x-forwarded-host, yyyy # 将请求头x-forwarded-host对应的值修改为yyyy- AddRequestParameter=customerId,9527001 # 新增请求参数Parameter:k ,v- RemoveRequestParameter=customerName # 删除url请求参数customerName,你传递过来也是null
5.1.3、回应头添加、修改、删除
- id: pay_routh3 #pay_routh3uri: lb://cloud-payment-service #匹配后提供服务的路由地址predicates:- Path=/pay/gateway/filter/** # 断言,路径相匹配的进行路由filters:- AddRequestHeader=X-Request-cjc1,cjcValue1 # 请求头kv,若一头含有多参则重写一行设置- AddRequestHeader=X-Request-cjc2,cjcValue2- RemoveRequestHeader=cache-control # 删除请求头cache-control- SetRequestHeader=x-forwarded-host, yyyy # 将请求头x-forwarded-host对应的值修改为yyyy- AddRequestParameter=customerId,9527001 # 新增请求参数Parameter:k ,v- RemoveRequestParameter=customerName # 删除url请求参数customerName,你传递过来也是null- AddResponseHeader=X-Response-cjc, BlueResponse # 新增请求参数X-Response-cjc并设值为BlueResponse- SetResponseHeader=Date,2099-11-11 # 设置回应头Date值为2099-11-11- RemoveResponseHeader=Content-Type # 将默认自带Content-Type回应属性删除
5.1.4、前缀和路径相关
- id: pay_routh3 #pay_routh3uri: lb://cloud-payment-service #匹配后提供服务的路由地址predicates:- Path=/pay/gateway/filter/** # 断言,路径相匹配的进行路由
# - Path=/gateway/filter/** # 断言,为配合PrefixPath测试过滤,暂时注释掉/pay
# - Path=/XYZ/abc/{segment} # 断言,为配合SetPath测试,{segment}的内容最后被SetPath取代filters:- RedirectTo=302, http://www.baidu.com/ # 访问http://localhost:9527/pay/gateway/filter跳转到http://www.baidu.com/
# - SetPath=/pay/gateway/{segment} # {segment}表示占位符,你写abc也行但要上下一致
# - PrefixPath=/pay # http://localhost:9527/pay/gateway/filter PrefixPath + Path
5.2、自定义过滤器
5.2.1、自定义全局过滤器
9527服务测试接口耗时代码
@Component
@Slf4j
public class MyGlobalFilter implements GlobalFilter, Ordered {private static final String BEGIN_VISIT_TIME = "begin_visit_time";@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {exchange.getAttributes().put(BEGIN_VISIT_TIME, System.currentTimeMillis());return chain.filter(exchange).then(Mono.fromRunnable(()-> {Long bvtime = exchange.getAttribute(BEGIN_VISIT_TIME);if (bvtime != 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() - bvtime) + "ms");log.info("我是美丽分割线: ###################################################");System.out.println();}}));}//数字越小,优先级越高@Overridepublic int getOrder() {return 0;}
}
5.2.2、自定义条件过滤器
9527服务测试代码
@Component
public class MyGatewayFilterFactory extends AbstractGatewayFilterFactory<MyGatewayFilterFactory.Config> {public MyGatewayFilterFactory() {super(MyGatewayFilterFactory.Config.class);}@Overridepublic List<String> shortcutFieldOrder() {return Arrays.asList("status");}@Overridepublic GatewayFilter apply(MyGatewayFilterFactory.Config config) {return new GatewayFilter() {@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {ServerHttpRequest request = exchange.getRequest();if (request.getQueryParams().containsKey("cjc")){return chain.filter(exchange);}else {exchange.getResponse().setStatusCode(HttpStatus.BAD_REQUEST);return exchange.getResponse().setComplete();}}};}public static class Config{@Getter@Setterprivate String status;//设置一个状态标志}
}
- id: pay_routh3 #pay_routh3uri: lb://cloud-payment-service #匹配后提供服务的路由地址predicates:- Path=/pay/gateway/filter/** # 断言,路径相匹配的进行路由
# - Path=/gateway/filter/** # 断言,为配合PrefixPath测试过滤,暂时注释掉/pay
# - Path=/XYZ/abc/{segment} # 断言,为配合SetPath测试,{segment}的内容最后被SetPath取代filters:- My=cjc