Gateway
---------------------------------------------------------------------------------------- ################### spring cloud Gateway ######################################### 反向代理 鉴权 流量控制 熔断 日志监控 三大核心概念 Route:路由 Predicate:谓词,断言 Filter:过滤器 路由转发+断言判断+执行过滤器链 <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> <exclusions> <exclusion> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> </exclusion> </exclusions> </dependency> <!-- 指标监控健康检查的actuator,网关是响应式编程删除掉spring-boot-starter-web dependency--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <!--lombok--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.28</version> <scope>provided</scope> </dependency> </dependencies> server: port: 9527 spring: application: name: cloud-gateway #以微服务注册进consul或nacos服务列表内 cloud: consul: #配置consul地址 host: localhost port: 8500 discovery: prefer-ip-address: true service-name: ${spring.application.name} @SpringBootApplication @EnableDiscoveryClient //服务注册和发现 public class Main9527 { public static void main(String[] args) { SpringApplication.run(Main9527.class,args); } } http://localhost:8500/ -------------------------- @RestController public class PayGateWayController { @Resource 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()); } } http://127.0.0.1:8001/pay/gateway/get/3 http://127.0.0.1:8001/pay/gateway/info server: port: 9527 spring: application: name: cloud-gateway #以微服务注册进consul或nacos服务列表内 cloud: consul: #配置consul地址 host: localhost port: 8500 discovery: prefer-ip-address: true service-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/** # 断言,路径相匹配的进行路由 http://127.0.0.1:9527/pay/gateway/get/3 http://127.0.0.1:9527/pay/gateway/info -------------------------- @FeignClient(value = "cloud-payment-service") public interface PayFeignApi { @GetMapping(value = "/pay/gateway/get/{id}") public ResultData getById(@PathVariable("id") Integer id); @GetMapping(value = "/pay/gateway/info") public ResultData<String> getGatewayInfo(); } @RestController public class OrderGateWayController { @Resource private 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(); } } http://localhost/feign/pay/gateway/get/1 http://localhost/feign/pay/gateway/info //@FeignClient(value = "cloud-payment-service") @FeignClient(value = "cloud-gateway") public interface PayFeignApi server: port: 9527 spring: application: name: cloud-gateway #以微服务注册进consul或nacos服务列表内 cloud: consul: #配置consul地址 host: localhost port: 8500 discovery: prefer-ip-address: true service-name: ${spring.application.name} gateway: routes: - id: pay_routh1 #pay_routh1 #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名 uri: lb://cloud-payment-service #匹配后提供服务的路由地址 predicates: - Path=/pay/gateway/get/** # 断言,路径相匹配的进行路由 - After=2023-12-30T23:02:39.079979400+08:00[Asia/Shanghai] # Before # Between - Cookie=username,zzyy - Header=X-Request-Id, \d+ # 请求头要有X-Request-Id属性并且值为整数的正则表达式 - Host=**.atguigu.com - Query=username, \d+ # 要有参数名username并且值还要是整数才能路由 - RemoteAddr=192.168.0.103/24 # 外部访问我的IP限制,最大跨度不超过32,目前是1~24它们是 CIDR 表示法。 - Method=GET,POST - My=gold - name: My args: userType: diamond - id: pay_routh2 #pay_routh2 #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名 uri: lb://cloud-payment-service #匹配后提供服务的路由地址 predicates: - Path=/pay/gateway/info/** # 断言,路径相匹配的进行路由 - id: pay_routh3 #pay_routh3 uri: lb://cloud-payment-service #匹配后提供服务的路由地址 predicates: - Path=/pay/gateway/filter/** # 断言,路径相匹配的进行路由,默认正确地址 filters: - AddRequestHeader=X-Request-atguigu1,atguiguValue1 # 请求头kv,若一头含有多参则重写一行设置 - AddRequestHeader=X-Request-atguigu2,atguiguValue2 - RemoveRequestHeader=sec-fetch-site # 删除请求头sec-fetch-site - SetRequestHeader=sec-fetch-mode, Blue-updatebyzzyy # 将请求头sec-fetch-mode对应的值修改为Blue-updatebyzzyy - AddRequestParameter=customerId,9527001 # 新增请求参数Parameter:k ,v - RemoveRequestParameter=customerName # 删除url请求参数customerName,你传递过来也是null - AddResponseHeader=X-Response-atguigu, BlueResponse # 新增请求参数X-Response-atguigu并设值为BlueResponse - SetResponseHeader=Date,2099-11-11 # 设置回应头Date值为2099-11-11 - RemoveResponseHeader=Content-Type # 将默认自带Content-Type回应属性删除 http://localhost/feign/pay/gateway/get/1 http://localhost/feign/pay/gateway/info curl http://127.0.0.1:9527/pay/gateway/get/3 --cookie "username=zzyy" curl http://127.0.0.1:9527/pay/gateway/get/3 -H "X-Request-Id:123456" curl http://127.0.0.1:9527/pay/gateway/get/3 -H "X-Request-Id:aabbcc" curl http://127.0.0.1:9527/pay/gateway/get/3 -H "Host:abcxxx.atguigu.com" curl http://127.0.0.1:9527/pay/gateway/get/3?username=123 http://192.168.0.103:9527/pay/gateway/get/3 //需求说明:自定义配置会员等级userTpye,按照钻/金/银和yml配置的会员等级,以适配是否可以访问 @Component public class MyRoutePredicateFactory extends AbstractRoutePredicateFactory<MyRoutePredicateFactory.Config> { public MyRoutePredicateFactory() { super(Config.class); } //这个Config类就是我们的路由断言规则,重要 @Validated public static class Config { @Setter@Getter@NotEmpty private String userType; //钻/金/银和yml配置的会员等级 } @Override public List<String> shortcutFieldOrder() { return Collections.singletonList("userType"); } @Override public Predicate<ServerWebExchange> apply(Config config) { return new Predicate<ServerWebExchange>() { @Override public boolean test(ServerWebExchange serverWebExchange) { //检查request的参数里面,userType是否为指定的值,符合配置就通过 //http://localhost:9527/pay/gateway/get/1?userType=diamond String userType = serverWebExchange.getRequest().getQueryParams().getFirst("userType"); if (userType == null) { return false; } //如果说参数存在,就和config的数据进行比较 if(userType.equalsIgnoreCase(config.getUserType())){ return true; } return false; } }; } } curl http://127.0.0.1:9527/pay/gateway/get/3?userType=diamond curl http://127.0.0.1:9527/pay/gateway/get/3?userType=gold 增加请求头过滤器AddRequestHeader PayGateWayController.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 +" "; } } 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("============================================="); return ResultData.success("getGatewayFilter 过滤器 test: "+result+" \t "+ DateUtil.now()); } - id: pay_routh3 #pay_routh3 uri: lb://cloud-payment-service #匹配后提供服务的路由地址 predicates: - Path=/pay/gateway/filter/** # 断言,路径相匹配的进行路由,默认正确地址 filters: - AddRequestHeader=X-Request-atguigu1,atguiguValue1 # 请求头kv,若一头含有多参则重写一行设置 - AddRequestHeader=X-Request-atguigu2,atguiguValue2 - RemoveRequestHeader=sec-fetch-site # 删除请求头sec-fetch-site - SetRequestHeader=sec-fetch-mode, Blue-updatebyzzyy # 将请求头sec-fetch-mode对应的值修改为Blue-updatebyzzyy - AddRequestParameter=customerId,9527001 # 新增请求参数Parameter:k ,v - RemoveRequestParameter=customerName # 删除url请求参数customerName,你传递过来也是null - AddResponseHeader=X-Response-atguigu, BlueResponse # 新增请求参数X-Response-atguigu并设值为BlueResponse - SetResponseHeader=Date,2099-11-11 # 设置回应头Date值为2099-11-11 - RemoveResponseHeader=Content-Type # 将默认自带Content-Type回应属性删除 http://localhost:9527/pay/gateway/filter http://localhost:9527/pay/gateway/filter?customerId=99999&customerName=zhan3 predicates: # - Path=/pay/gateway/filter/** # 断言,路径相匹配的进行路由,默认正确地址 - Path=/gateway/filter/** # 断言,为配合PrefixPath测试过滤,暂时注释掉/pay filters: - PrefixPath=/pay # http://localhost:9527/pay/gateway/filter 被分拆为: PrefixPath + Path http://localhost:9527/gateway/filter http://localhost:9527/gateway/filter?customerId=99999&customerName=zhan3 predicates: - Path=/XYZ/abc/{segment} # 断言,为配合SetPath测试,{segment}的内容最后被SetPath取代 filters: - SetPath=/pay/gateway/{segment} # {segment}表示占位符,你写abc也行但要上下一致 http://localhost:9527/XYZ/abc/filter predicates: - Path=/pay/gateway/filter/** # 断言,路径相匹配的进行路由,默认正确地址 filters: - RedirectTo=302, http://www.atguigu.com/ # 访问http://localhost:9527/pay/gateway/filter跳转到http://www.atguigu.com/ 自定义全局过滤器 @Component @Slf4j public class MyGlobalFilter implements GlobalFilter, Ordered { public static final String BEGIN_VISIT_TIME = "begin_visit_time";//开始调用方法的时间 @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { //1 先记录下访问接口的开始时间 exchange.getAttributes().put(BEGIN_VISIT_TIME,System.currentTimeMillis()); //2 返回统计的各个结果给后台 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(); } })); } /** * 数字越小,优先级越高 * @return */ @Override public int getOrder() { return 0; } } http://localhost:9527/pay/gateway/info http://localhost:9527/pay/gateway/get/3 http://localhost:9527/pay/gateway/filter 自定义条件过滤器 @Component public class MyGatewayFilterFactory extends AbstractGatewayFilterFactory<MyGatewayFilterFactory.Config> { public MyGatewayFilterFactory() { super(Config.class); } @Override public GatewayFilter apply(Config config) { return new GatewayFilter() { @Override public 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(); } } }; } @Override public List<String> shortcutFieldOrder() { return Arrays.asList("status"); } public static class Config { @Getter@Setter private String status;//设定一个状态值/标志位,它等于多少,匹配和才可以访问 } } //单一内置过滤器GatewayFilter predicates: - Path=/pay/gateway/filter/** # 断言,路径相匹配的进行路由,默认正确地址 filters: - My=atguigu http://localhost:9527/pay/gateway/filter http://localhost:9527/pay/gateway/filter?atguigu=java ----------------------------------------------------------------------------------------
posted on 2025-12-21 21:30 yebinghuai-qq-com 阅读(0) 评论(0) 收藏 举报
浙公网安备 33010602011771号