统一网关Gateway
网关功能:
- 身份认证和权限校验
- 服务路由,负载均衡
- 请求限流
网关的技术实现:
-
gateway(较新)
-
zuul
基于Servlet的实现,属于阻塞式编程。而SpringCloudGateway则是基于Spring5中提供的WebFlux,属于响应式编程的实现具备更好的性能。
搭建网关服务:
-
创建新的module,引入SpringCloudGateway的依赖和nacos的服务发现依赖:
<!-- nacos服务发现依赖--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <!-- 网关Gateway依赖--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency>
-
路由的配置:
-
路由id:路由的唯一标识
-
路由目标(uri):路由的目标地址,http代表固定地址,lb代表根据服务名负载均衡
-
路由断言(predicates):判断路由的规则,
-
路由过滤器(filters):对相应或请求做处理
server: port: 10010 spring: application: name: gateway cloud: nacos: server-addr: localhost:8848 gateway: routes: - id: user-service # 路由标识,必须唯一 uri: lb://userservice # 路由的目标地址,服务名 predicates: # 路由断言,判断请求是否符合规则。 - Path=/user/** # 路径断言,判断路径是否以/user开头,如果是则符合规则 - id: order-service uri: lb://orderserve predicates: - Path=/order/**
-
路由断言工厂 Route Predicate Factory
在配置文件中写的断言规则只是字符串,这些字符串会被Predicate Factory读取并处理,转变为路由断言的条件
名称 | 说明 | 示例 |
---|---|---|
After | 是某个时间点后的请求 | -After=2037-01-20T17:42:47.789-07:00[America/Denver] |
Before | 是某个时间点之前的请求 | -Before=2031-04-13T15:14:47.433+08:00Asia/Shanghai] |
Between | 是某两个时间点之前的请求 | -Between=2037-01-20T17:42:47.789-07:00[America/Denver],2037-01-21T17:42:47.789-07:00 America./Denver] |
Cookie | 请求必须包含某些cookie | - Cookie=chocolate,ch.p |
Header | 请求必须包含某些header | - Header=X-Request-ld,\d+ |
Host | 请求必须是访问某个host(域名) | - Host=“.somehost.org,”".anotherhost.org |
Method | 请求方式必须是指定方式 | - Method=GET,POST |
Path | 请求路径必须符合指定规则 | -Path=/red/(segment),/blue/** |
Query | 请求参数必须包含指定参数 | -Query=name,Jack或者-Query=name |
RemoteAddr | 请求者的ip必须是指定范围- | -RemoteAddr=192.168.1.1/24 |
Weight | 权重处理 |
路由过滤器 GatewayFilter
GatewayFilter 是网关中提供的一种过滤器,可以对进入网关的请求和微服务返回的响应做处理。
-
某个微服务的过滤器
spring: application: name: gateway cloud: nacos: server-addr: localhost:8848 gateway: routes: - id: user-service # 路由标识,必须唯一 uri: lb://userservice # 路由的目标地址,服务名 predicates: # 路由断言,判断请求是否符合规则。 - Path=/user/** # 路径断言,判断路径是否以/user开头,如果是则符合规则 filters: - AddRequestHeader=Truth,cyt is freaking aowsome
-
全局过滤器
spring: application: name: gateway cloud: nacos: server-addr: localhost:8848 gateway: routes: - id: user-service # 路由标识,必须唯一 uri: lb://userservice # 路由的目标地址,服务名 predicates: # 路由断言,判断请求是否符合规则。 - Path=/user/** # 路径断言,判断路径是否以/user开头,如果是则符合规则 - id: order-service uri: lb://orderserve predicates: - Path=/order/** - Before=2037-01-20T17:42:47.789-07:00[America/Denver] # 路由断言,判断是否在规定时间之前 default-filters: # 全局过滤器配置 - AddRequestHeader=Truth,cyt is freaking aowsome
全局过滤器 GlobalFilter
全局过滤器的作用也是处理一切进入网关的请求和微服务响应,与GatewayFilter的作用一样。
区别在于GatewayFilteri通过配置定义,处理逻辑是固定的。而GlobalFilter的逻辑需要自己写代码实现。
-
代码实现
-
在gateway项目中创建AuthorizeFilter类
//@Order(-1) //设置优先级 @Component //注册到SPring中成为一个Bean public class AuthorizeFilter implements GlobalFilter, Ordered { @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { //获取请求参数 ServerHttpRequest request = exchange.getRequest(); MultiValueMap<String, String> params = request.getQueryParams(); //获取参数中的 authorization 参数 String authorization = params.getFirst("authorization"); //判断authorization的值是否等于admin if ("admin".equals(authorization)){ //是则放行 return chain.filter(exchange); } //不是则拦截 //设置状态码 exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED); return exchange.getResponse().setComplete(); } @Override public int getOrder() { return -1; } }
过滤器的执行顺序
请求进入网关会碰到三类过滤器:当前路由的过滤器、DefaultFilter、GlobalFilter
请求路由后,会将当前路由过滤器和DefaultFilter、GlobalFilter,合并到一个过滤器链(集合)中,排序后依次执行
每个过滤器
-
每一个过滤器都必须指定一个int类型的orderf值,order值越小,优先级越高,执行顺序越靠前。
-
GlobalFilteri通过实现Ordered接口,或者添加@Orderi注解来指定order值,由我们自己指定
-
路由过滤器和defaultFilter的order由Spring指定,默认是按照声明顺序从1递增。
-
当过滤器的order值一样时,会按照defaultFilter>路由过滤器>GlobalFilter的顺序执行。
-
org.springframework.cloud.gateway.route.RouteDefinitionRouteLocator#getFilters()先加载defaultFilters,然后再加载某个route的filters,然后合并。
-
org.springframework.cLoud.gateway.handler.FilteringWebHandler#handle()方法会加载全局过滤器,与前面的过滤器合并后根据order排序,组织过滤器链
跨域问题处理
浏览器禁止请求的发起者与服务端发生跨域∂jax请求,请求被浏览器拦截的问题
-
跨域问题处理配置
gateway: routes: - id: user-service # 路由标识,必须唯一 uri: lb://userservice # 路由的目标地址,服务名 predicates: # 路由断言,判断请求是否符合规则。 - Path=/user/** # 路径断言,判断路径是否以/user开头,如果是则符合规则 - id: order-service uri: lb://orderserve predicates: - Path=/order/** - Before=2037-01-20T17:42:47.789-07:00[America/Denver] # 路由断言,判断是否在规定时间之前 default-filters: # 全局过滤器配置 - AddRequestHeader=Truth,cyt is freaking aowsome globalcors: # 全局的跨域处理 add-to-simple-url-handler-mapping: true # 解决options请求被拦截问题 corsConfigurations: '[/**]': allowed-origins: # 允许哪些网站的跨域请求 - "http://localhost:8090" - "http://www.leyou.com" allowed-methods: # 允许的跨域ajax的请求方式 - "GET" - "POST" - "DELETE" - "PUT" - "OPTIONS" allowed-headers: "*" # 允许在请求中携带的头信息 allowCredentials: true # 是否允许携带cookie maxAge: 360000 # 这次跨域检测的有效期