Gateway的介绍:
1. 为什么需要Gateway?
在微服务架构中,微服务系统的开发存在如下问题:
1. 每一个微服务都有各自的端口,导致端口太多,不易维护;
2. 跨域问题的解决;
3. 权限的问题解决;
2. Gateway的作用:
Gateway其实就是一个微服务系统,接收所有的请求,根据URL进行路由,转发到相应的微服务系统进行处理;
3. 实现网关的技术:
ngnix;
spring cloud gateway
spring cloud zuul
...
4. spring cloud gateway中的概念:
路由:可以理解为转发请求;
断言:可以理解为符合某种条件才进行路由;
过滤:转发请求的时候需要对请求本身进行处理;
5. spring cloud gateway的使用:
1. 创建工程it-spring-cloud-gateway,添加依赖,因为父工程已经添加了公共的依赖,所以子工程只需添加自身需要的依赖即可:
<dependencies>
<!--网关依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!-- Eureka客户端 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
</dependencies>
2. 创建配置文件application.yml,配置端口及应用名称,并将网关微服务注册给Eureka:
# 注释版本
server:
port: 18084
spring:
application:
name: api-gateway # 应用名
# Eureka服务中心配置
eureka:
client:
service-url:
# 注册Eureka Server集群
defaultZone: http://127.0.0.1:7001/eureka
3. 创建启动类,并在启动类开启Eureka客户端
package com.it;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
/**
* ToDo
*
* @author Lyle
* @date 2020/4/4
*/
@SpringBootApplication
@EnableEurekaClient
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class,args);
}
}
4. 路由规则配置:
在application.yml中进行如下配置:
# 注释版本
server:
port: 18084
spring:
application:
name: api-gateway # 应用名
cloud:
gateway:
routes:
#id唯一标识,可自定义,可以配置多个,这里只配置一个为例
- id: user-service-route
#路由的服务地址,即:符合条件就转发请求到这个地址
# uri: http://localhost:18082
uri: lb//user-consumer # 若配置了集群,有多个微服务,可以使用名称配置,此处18082对应的微服务名为user-consumer
# 路由拦截的地址配置(断言):判断条件是否满足
# 例如:请求为:http://localhost:18084/feign/123,满足断言要求,转发到http://localhost:18081/feign/123
predicates:
- Path=/feign/**
#- id: user-service-route2
5. 过滤器:
1.自带的过滤器:
全局过滤器;
局部过滤器;
配置文件:
# 注释版本
server:
port: 18084
spring:
application:
name: api-gateway # 应用名
cloud:
gateway:
# 配置全局默认过滤器,所有请求都要经过该过滤器进行处理
default-filters:
# 往响应过滤器中加入信息:X-Response-Default-MyName,值为lyle
- AddResponseHeader=X-Response-Default-MyName,lyle
routes:
#id唯一标识,可自定义,可以配置多个,这里只配置一个为例
- id: user-service-route
#路由的服务地址,即:符合条件就转发请求到这个地址
# uri: http://localhost:18082
uri: lb://user-consumer # 若配置了集群,有多个微服务,可以使用名称配置,此处18082对应的微服务名为user-consumer
# 路由拦截的地址配置(断言):判断条件是否满足
# 例如:请求为:http://localhost:18084/feign/123,满足断言要求,转发到http://localhost:18081/feign/123
predicates:
#- Path=/feign/**
- Path=/**
filters:
# 请求地址添加路径前缀过滤器
# 请求为:http://localhost:18084/test,添加前缀并转发:转发到http://localhost:18081/feign/test
# - PrefixPath=/feign
# 去除路径前缀过滤器,1表示去除1个
# http://localhost:18084/api/test,去除前缀并转发:转发到http://localhost:18081/test
- StripPrefix=1
#- id: user-service-route2
# Eureka服务中心配置
eureka:
client:
service-url:
# 注册Eureka Server集群
defaultZone: http://127.0.0.1:7001/eureka
2.自定义过滤器:
全局过滤器;
局部过滤器;
自定义全局过滤器的实现:
在微服务it-spring-cloud-gateway中定义类交给spring管理,这个类实现接口GlobalFilter和Ordered接口,重写方法处理业务:
package com.it.filter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
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.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
/**
* ToDo
*
* @author Lyle
* @date 2020/4/4
*/
@Component
public class MyGlobalFilter implements GlobalFilter, Ordered {
//该方法用于接收所有的请求进行业务处理
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
//模拟权限判断,只要请求中携带了token,并且值为1234就放行
//1.获取请求对象 request
ServerHttpRequest request = exchange.getRequest();
//2.获取响应对象 response
ServerHttpResponse response = exchange.getResponse();
//获取请求参数中token的值,判断并处理
String token = request.getQueryParams().getFirst("token");
if (!StringUtils.isEmpty(token)&&token.equals("1234")){
//有权限,放行
return chain.filter(exchange);
}else {
//没有权限
response.setStatusCode(HttpStatus.UNAUTHORIZED);
//完成请求
return response.setComplete();
}
}
//用于执行过滤器的顺序的判断:过滤器链
@Override
public int getOrder() {
return 0;
}
}