核心概念
- Spring Cloud Gateway旨在为微服务架构提供简单、有效和统一的API路由管理方式
- 供统一的路由方式,并且还基于Filter链的方式提供了网关基本的功能,例如:安全、监控/埋点、限流等。
- 前端请求都请求到该微服务中,该微服务再负责转发到别的服务中去
- 和 Zuul 区别:
- Zuul:拦截单个url规则、默认去除拦截前缀、重复的url规则后面的会将前面覆盖
- Gateway:拦截多个url规则、默认不去除拦截前缀、重复url规则前面的会将后面覆盖
- 规则:
- 断言的条件必须全部满足,才会路由转发
- 所有的断言规则,必须全部为真,才能够进行请求转发
- 只要断言为假,就会返回404状态码
简单用法
导入依赖
| |
| <dependency> |
| <groupId>org.springframework.cloud</groupId> |
| <artifactId>spring-cloud-starter-gateway</artifactId> |
| </dependency> |
| |
| <dependency> |
| <groupId>org.springframework.cloud</groupId> |
| <artifactId>spring-cloud-starter-loadbalancer</artifactId> |
| </dependency> |
配置application.yml
| spring: |
| cloud: |
| |
| gateway: |
| |
| routes: |
| |
| - id: toBaidu |
| |
| predicates: |
| |
| - Path: / |
| uri: https://www.baidu.com |
| - id: toGoogle |
| predicates: |
| |
| - Path: /, /guonei, /guoji |
| uri: https://www.google.com |
| - id: toConsumer |
| predicates: |
| |
| |
| - Path: /consumer/** |
| uri: http://localhost:8002 |
更多应用
实现负载均衡
| spring: |
| cloud: |
| gateway: |
| routes: |
| - id: toConsumer |
| predicates: |
| - Path: /consumer/** |
| |
| |
| |
| |
| |
| uri: lb://eureka-client-consumer |
更多断言规则
| spring: |
| cloud: |
| gateway: |
| routes: |
| - id: toConsumer |
| |
| |
| predicates: |
| - Path=/consumer/** |
| |
| |
| - After=2021-12-23T14:44:47.789-07:00[Asia/Shanghai] |
| |
| - Before=2021-12-23T14:51:47.789-07:00[Asia/Shanghai] |
| |
| - Between=2021-12-23T14:51:47.789-07:00[Asia/Shanghai], 2021-12-23T15:00:47.789-07:00[Asia/Shanghai] |
| |
| - Cookie=abc, bcd |
| |
| - Header=X-Request-Id, abc |
| |
| - Method=GET, POST |
| |
| - Query=aaa, bbb |
| uri: http://localhost:8002 |
实现过滤器
| spring: |
| cloud: |
| gateway: |
| routes: |
| - id: toConsumer |
| predicates: |
| - Path=/consumer/**, /api/** |
| uri: lb://eureka-client-consumer |
| |
| filters: |
| |
| - AddRequestHeader=X-Request-Header, blue |
| |
| - AddRequestParameter=key1, value1 |
| |
| - AddResponseHeader=ccc, ddd |
| |
| - PrefixPath=/api |
| |
| |
| - StripPrefix=1 |
| |
| |
| - RewritePath=/api/abc/?(?<segment>.*), /consumer/$\{segment} |
| |
| - SetStatus=401 |
| |
| |
| |
| - name: RequestRateLimiter |
| args: |
| |
| |
| redis-rate-limiter.replenishRate: 1 |
| |
| redis-rate-limiter.burstCapacity: 2 |
| |
| redis-rate-limiter.requestedTokens: 1 |
| |
| key-resolver: "#{@xxx}" |
以上Redis网关限流需先注入 key-resolver 对象
| |
| @Bean |
| KeyResolver userKeyResolver() { |
| return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("user")); |
| } |
实现自定义全局过滤器
| @Slf4j |
| @Configuration |
| public class CustomFilter implements GlobalFilter, Ordered { |
| |
| @Override |
| public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { |
| log.info("过滤器执行了..."); |
| |
| |
| String token = exchange.getRequest().getQueryParams().getFirst("token"); |
| |
| if(token == null){ |
| return errorInfo(exchange,1,"Token校验失败..."); |
| } |
| |
| |
| return chain.filter(exchange); |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| @Override |
| public int getOrder() { |
| return 0; |
| } |
| |
| public Mono<Void> errorInfo(ServerWebExchange exchange, Integer code, String message) { |
| |
| |
| Map<String, Object> errorMap = new HashMap<>(); |
| errorMap.put("code", code); |
| errorMap.put("message", message); |
| errorMap.put("data", null); |
| |
| |
| return Mono.defer(() -> { |
| byte[] bytes = null; |
| try { |
| |
| bytes = new ObjectMapper().writeValueAsBytes(errorMap); |
| } catch (JsonProcessingException e) { |
| e.printStackTrace(); |
| } |
| |
| ServerHttpResponse response = exchange.getResponse(); |
| response.getHeaders().add("Content-Type", MediaType.APPLICATION_PROBLEM_JSON_UTF8.toString()); |
| |
| DataBuffer wrap = response.bufferFactory().wrap(bytes); |
| return response.writeWith(Flux.just(wrap)); |
| }); |
| |
| } |
| } |
扩展:SpringSession的校验
同一台机器不同微服务所使用的session空间不相同,无法共享数据,此时我们可以使用 SpringSession 来解决
示意图如下:


用法:
引入依赖
| |
| <dependency> |
| <groupId>org.springframework.boot</groupId> |
| <artifactId>spring-boot-starter-data-redis</artifactId> |
| </dependency> |
| |
| <dependency> |
| <groupId>org.springframework.session</groupId> |
| <artifactId>spring-session-data-redis</artifactId> |
| </dependency> |
启动类加上注解
| |
| @EnableRedisHttpSession |
| public class Application { |
此时存取session的数据都是从同一个redis中存取
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek “源神”启动!「GitHub 热点速览」
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 我与微信审核的“相爱相杀”看个人小程序副业
· C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)
· spring官宣接入deepseek,真的太香了~