spring cloud Gateway简单使用
一、引子
2年前有幸使用过一次Spring Cloud (1.5.9),1.* 集成的是ZUUL做网关。终于在2年后,这次果断使用Spring Cloud Gateway。
区别:
Zuul构建于 Servlet 2.5,兼容 3.x,使用的是阻塞式的 API,不支持长连接,比如 websockets。
Spring Cloud Gateway构建于 Spring 5+,基于 Spring Boot 2.x 响应式的、非阻塞式的 API。支持 websockets,和Spring 框架紧密集成。底层使用netty模型,性能极高。
备注:
一个简单的创业项目架构图如下:
二、Gateway设计思想
2.1 官网设计
自从撇开netflex zuul后,spring Cloud速度搜搜的。我开发时还是用2.1.4,目前最新已经到2.2.1,附上官网飞机票
2.1.1 特性
Built on Spring Framework 5, Project Reactor and Spring Boot 2.0:基于 Spring Framework 5,Project Reactor 和 Spring Boot 2.0
Able to match routes on any request attribute.:能匹配任意请求属性的路由
Predicates and filters are specific to routes.:针对特定路由使用匹配策略和过滤器
Hystrix Circuit Breaker integration. :集成Hystri断路器
Spring Cloud DiscoveryClient integration:集成服务发现(gateway一样可注册到eureka)
Easy to write Predicates and Filters:易于写策略(断言)+过滤器
Request Rate Limiting 请求限流
Path Rewriting:重写path
简单来说就是Route、Predicate、Filter三大核心组件。
2.1.2 流程图
如上图,Gateway Client客户端发送请求在Gateway Handler Mapping中查找是否命中路由策略,命中的话请求转发给Gateway Web Handler来处理。根据定义的多个Filter链,执行顺序:Pre Filter->代理请求->Post Filter。
2.1.3 内置Predicates+Filter
Gateway内置了11个Predicates Factories路由策略(断言)工厂类。
Filter分2类:
- 31个GatewayFilter Factories网关过滤器工厂类
- 10个GlobalFilter 全局过滤器接口
这里就不在过多介绍,建议有需求时可以去官网找找,没有的话再自己开发。
2.2 我们的使用
1.使用Route结合Hystrix实现默认降级策略
2.使用GatewayFilter接口,自定义过滤器类,实现登录态(token)校验
三、Gateway简单使用
3.1 实现微服务的默认降级策略
spring:
cloud:
gateway:
discovery:
locator:
enabled: false
#开启小写验证,默认feign根据服务名查找都是用的全大写
lowerCaseServiceId: true
default-filters:
- AddResponseHeader=X-Response-Default-Foo, Default-Bar
routes:
- id: OLOAN-FINANCIAL-PRODUCT-SERVICE
# lb代表从注册中心获取服务
uri: lb://OLOAN-FINANCIAL-PRODUCT-SERVICE
predicates:
# 转发该路径
- Path=/gateway/financialProduct/**
# 带前缀
filters:
- StripPrefix=1
- name: Hystrix
args:
name: fallbackcmd
fallbackUri: forward:/defaultfallback
- id: ADMIN-SERVICE
uri: lb://ADMIN-SERVICE
predicates:
- Path=/gateway/auth/**
filters:
- StripPrefix=2
- name: Hystrix
args:
name: fallbackcmd
fallbackUri: forward:/defaultfallback
如上图,我们开启了2个微服务route路由。
- 1)前端请求时path带/gateway/,在gateway层使用StripPrefix=1,去掉gateway,最终微服务上的path不带"/gateway/".
- 2)使用Hystrix实现默认降级策略,降级接口实现如下:
@Slf4j
@RestController
public class DefaultHystrixController { @RequestMapping("/defaultfallback")
public ApiResult defaultfallback(){ log.info("服务降级中");
return ApiResult.failure("服务异常");
}
}
3.2 实现登录态(token)校验
3.2.1 自定义过滤器
自定义过滤器,实现GatewayFilter, Ordered 2个接口。
import com.*.auth.UserTokenTools;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.core.Ordered;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono; /**
* @author denny.zhang
* @Description token过滤器
* @date 2019/12/12 13:55
*/
@Slf4j
@Component
public class LoginTokenFilter implements GatewayFilter, Ordered { private static final String AUTHORIZE_TOKEN = "Authorization";
private static final String BEARER = "Bearer "; /**
* token过滤
*
* @param exchange
* @param chain
* @return
*/
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
log.info("当前环境已开启token校验");
ServerHttpRequest request = exchange.getRequest();
HttpHeaders headers = request.getHeaders();
ServerHttpResponse response = exchange.getResponse();
// 取Authorization
String tokenHeader = headers.getFirst(AUTHORIZE_TOKEN);
log.info("tokenHeader=" + tokenHeader);
// token不存在
if (StringUtils.isEmpty(tokenHeader)) {
response.setStatusCode(HttpStatus.UNAUTHORIZED);
return response.setComplete();
}
// 取token
String token = this.getToken(tokenHeader);
log.info("token=" + token); // token不存在
if (StringUtils.isEmpty(token)) {
log.info("token不存在");
response.setStatusCode(HttpStatus.UNAUTHORIZED);
return response.setComplete();
}
// 校验 token是否失效
if (UserTokenTools.isTokenExpired(token, null)) {
log.info("token失效");
response.setStatusCode(HttpStatus.UNAUTHORIZED);
return response.setComplete();
}
// 校验 token是否正确
if (!UserTokenTools.checkToken(token, null)) {
response.setStatusCode(HttpStatus.UNAUTHORIZED);
return response.setComplete();
} // //有token 这里可根据具体情况,看是否需要在gateway直接把解析出来的用户信息塞进请求中,我们最终没有使用
// UserTokenInfo userTokenInfo = UserTokenTools.getUserTokenInfo(token);
// log.info("token={},userTokenInfo={}",token,userTokenInfo);
// request.getQueryParams().add("token",token);
//request.getHeaders().set("token", token);
return chain.filter(exchange);
} @Override
public int getOrder() {
return -10;
} /**
* 解析Token
*/
public String getToken(String requestHeader) {
//2.Cookie中没有从header中获取
if (requestHeader != null && requestHeader.startsWith(BEARER)) {
return requestHeader.substring(7);
}
return "";
}
}
上图中,UserTokenTools是我们自定义的一个JWT工具类,用来生成token,校验token过期、正确等。
3.2.2 配置路由
大家可根据具体情况,如果只有一套登录态,那就用一个filter即可。
import com.*.gateway.filter.AuthorizeGatewayFilter;
import com.*.gateway.filter.LoginTokenFilter;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; @Configuration
public class GatewayConfig { @Bean
public RouteLocator getRouteLocator(RouteLocatorBuilder builder) {
return builder.routes()
// token校验1
.route(predicateSpec -> predicateSpec
.path("/gateway/pay/card/**", "/gateway/app/**")
.filters(gatewayFilterSpec -> gatewayFilterSpec.stripPrefix(1).filter(new AuthorizeGatewayFilter()))
.uri("lb://OLOAN-PAY-SERVICE")
.id("OLOAN-PAY-SERVICE-token")) // token校验2
.route(predicateSpec -> predicateSpec
.path("/gateway/order-audit/**", "/gateway/order/**", "/gateway/order-payment/**")
.filters(gatewayFilterSpec -> gatewayFilterSpec.stripPrefix(1).filter(new LoginTokenFilter()))
.uri("lb://OLOAN-ORDER-SERVICE")
.id("OLOAN-ORDER-ORDER-token"))
.build();
}
}
四、总结
4.1.WebFlux
Spring Cloud Gateway使用WebFlux,和spring boot web包冲突,使用时一定记得pom中排除原来老WEB那一套(servlet)相关jar,否则会报错。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
</exclusion>
</exclusions>
</dependency>
4.2.Gateway Filter
Gateway Filter 自带的源码支撑错误码response.setStatusCode(HttpStatus.UNAUTHORIZED);并不是那么的友好。错误码枚举使用的是spring自带框架的枚举类:
org.springframework.http.HttpStatus:
UNAUTHORIZED(401, "Unauthorized")
这样请求返回的结构体和一般定义的JSON格式(code message data)不同。当然官方也是提供了解决方案。后续再去优化吧。
4.3 限流
gateway默认实现了几个简单的限流策略(依赖redis),后续可以使用一下。
spring cloud Gateway简单使用的更多相关文章
- Spring Cloud Gateway简单入门,强大的微服务网关
我最新最全的文章都在南瓜慢说 www.pkslow.com,欢迎大家来喝茶! 1 简介 见名知义,Spring Cloud Gateway是用于微服务场景的网关组件,它是基于Spring WebFlu ...
- 简单尝试Spring Cloud Gateway
简单尝试Spring Cloud Gateway 简介 Spring Cloud Gateway是一个API网关,它是用于代替Zuul而出现的.Spring Cloud Gateway构建于Sprin ...
- Spring Cloud Gateway的动态路由怎样做?集成Nacos实现很简单
一.说明 网关的核心概念就是路由配置和路由规则,而作为所有请求流量的入口,在实际生产环境中为了保证高可靠和高可用,是尽量要避免重启的,所以实现动态路由是非常有必要的:本文主要介绍 Spring Clo ...
- Spring Cloud Gateway + Nacos(1)简单配置
当初我学习时候就是参考这位大佬的博客: Nacos集成Spring Cloud Gateway 基础使用 现在学习到spring cloud alibaba 使用nacos做服务中心,dubbo做通信 ...
- 从0开始构建你的api网关--Spring Cloud Gateway网关实战及原理解析
API 网关 API 网关出现的原因是微服务架构的出现,不同的微服务一般会有不同的网络地址,而外部客户端可能需要调用多个服务的接口才能完成一个业务需求,如果让客户端直接与各个微服务通信,会有以下的问题 ...
- api网关揭秘--spring cloud gateway源码解析
要想了解spring cloud gateway的源码,要熟悉spring webflux,我的上篇文章介绍了spring webflux. 1.gateway 和zuul对比 I am the au ...
- SpringCloud无废话入门05:Spring Cloud Gateway路由、filter、熔断
1.什么是路由网关 截至目前为止的例子中,我们创建了一个service,叫做:HelloService,然后我们把它部署到了两台服务器(即提供了两个provider),然后我们又使用ribbon将其做 ...
- Spring Cloud Gateway入门
1.什么是Spring Cloud GatewaySpring Cloud Gateway是Spring官方基于Spring 5.0,Spring Boot 2.0和Project Reactor等技 ...
- Spring Cloud Gateway服务网关
原文:https://www.cnblogs.com/ityouknow/p/10141740.html Spring 官方最终还是按捺不住推出了自己的网关组件:Spring Cloud Gatewa ...
随机推荐
- Save and Load from XML
using UnityEngine; using System.Collections; using System.Xml; using System.Xml.Serialization; using ...
- 2018-8-10-WPF-修改按钮按下的颜色
title author date CreateTime categories WPF 修改按钮按下的颜色 lindexi 2018-08-10 19:16:53 +0800 2018-03-15 2 ...
- HZOJ big
考试的时候理解错题了(无语)…… 那个看似很长的式子的意义其实是逻辑左移动,就是最高位会出现在最低位的意思(这谁能看出来……).此时x取值经过那个式子后仍然可以遍历[0,2^n), O(m)枚举断点, ...
- python特性(八):生成器对象的send方法
生成器对象是一个迭代器.但是它比迭代器对象多了一些方法,它们包括send方法,throw方法和close方法.这些方法,主要是用于外部与生成器对象的交互.本文先介绍send方法. send方法有一个参 ...
- [学习笔记]整体DP
问题: 有一些问题,通常见于二维的DP,另一维记录当前x的信息,但是这一维过大无法开下,O(nm)也无法通过. 但是如果发现,对于x,在第二维的一些区间内,取值都是相同的,并且这样的区间是有限个,就可 ...
- Pytorch Bi-LSTM + CRF 代码详解
久闻LSTM + CRF的效果强大,最近在看Pytorch官网文档的时候,看到了这段代码,前前后后查了很多资料,终于把代码弄懂了.我希望在后来人看这段代码的时候,直接就看我的博客就能完全弄懂这段代码. ...
- [转]SpringBoot整合Swagger2以及生产环境的安全问题处理
1.创建springboot项目 https://www.cnblogs.com/i-tao/p/8878562.html 这里我们使用多环境配置: application-dev.yml(开发环境) ...
- P1110 变身
题目描述 给你一个长度为n的数组a,他们的坐标从1到n,并且他们的数值也在1到n之间且两两不同. 数组中的每个元素每轮回合都会变身,变身的结果取决于该元素当前的值,如果在某一个回合该元素的值为u,则下 ...
- ES6 set和map数据结构对对象数组去重简单实现
自从有了es6的set数据结构,数组的去重可以简单用一行代码实现,比如下面的方式 let arr = [1, 2, 2, 3, 4] function unique (arr) { return [. ...
- React MVC框架 <某某后台商品管理开源项目> 完成项目总结
**百货后台商品信息开源项目 1.利用React app脚手架 2.封装打包 buid 3.更偏向于后台程序员开发思维 4.利用的 react -redux react-router-dom ...