1、为什么需要网关
身份认证、权限校验;
服务路由、负载均衡;
请求限流。
2、网关的技术实现
gateway,zuul
Zuul 是基于Servlet实现的,属于阻塞式编程;
Spring Cloud Gateway 则是基于Spring5中提供的WebFlux实现的,属于响应式编程,具备更好的性能。
3、搭建Gateway网关
1、创建新的module,引入Spring Cloud Gateway依赖和nacos的服务发现依赖;
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!--由于springcloud2020弃用了Ribbon,因此Alibaba在2021版本nacos中删除了Ribbon的jar包
导致无法通过lb路由到指定微服务,出现了503情况。
引入springcloud loadbalancer包来解决即可-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
2、resources目录下,新建application.yml文件
server:
port: 10000 #端口号
spring:
application:
name: gateway-server #服务名
cloud:
nacos:
discovery:
server-addr: localhost:8848 #nacos注册中心地址
gateway:
routes: #路由配置
- id: order-server #路由id,自定义,唯一即可
uri: lb://order-server #路由的目标服务,lb就是负载均衡,order-server是服务名称
predicates: #路由断言,判断请求地址是否符合路由规则的条件
- Path=/api/order/** #这个是按照路径匹配,只要以/api/order开头的请求地址就符合要求
filters: #路由过滤器,处理请求或响应
#路径重写 例如:localhost:10000/api/a,重写后:localhost:10000/a
- RewritePath=/api/(?<segment>.*),/$\{segment}
3、创建启动类
@SpringBootApplication
@EnableDiscoveryClient
public class GatewayApp {
public static void main(String[] args) {
SpringApplication.run(GatewayApp.class, args);
}
}
4、路由断言工厂Route Predicate Factory
我们在配置文件中写的断言规则只是字符串,这些字符串会被Predicate Factory读取并处理,转变为路由判断的条件。
例如Path=/user/**是按照路径匹配,这个规则是由:org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory类来处理的,像这样的断言工厂在SpringCloudGateway还有十几个。
Spring提供了11种基本的Predicate工厂:
5、过滤器
1、路由过滤器 GatewayFilter
GatewayFilter是网关中提供的一种过滤器,可以对进入网关的请求和微服务返回的响应做处理
Spring提供了31种不同的路由过滤器工厂:
2、默认过滤器
如果要对所有的路由都生效,则可以将过滤器工厂写到default下。格式如下:
3、全局过滤器 GlobalFilter
全局过滤器的作用也是处理一切进入网关的请求和微服务响应,与GatewayFilter的作用一样。
区别在于GatewayFilter是通过配置定义的,处理逻辑固定。而GlobalFilter的逻辑需要自己写代码实现。
定义方式是实现GlobalFilter接口:
//排序(注解,实现接口两种方式)
//@Order(-1)
@Component
public class GatewayFilter implements GlobalFilter, Ordered {
/**
* 处理当前请求 通过GatewayFilterChain将请求交给下一个过滤器处理
*
* @param exchange 请求上下文,里面可以获取Request、Response等信息
* @param chain 用来把请求委托给下一个过滤器
* @return {@code Mono<Void>} 返回标示当前过滤器业务结束
* */
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
//获取请求参数
//exchange.getRequest().getHeaders().getFirst("authorization");
//exchange.getRequest().getQueryParams().getFirst("key");
//放行
//chain.filter(exchange);
//拦截
//exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
//return exchange.getResponse().setComplete();
return null;
}
@Override
public int getOrder() {
return -1;
}
}
4、过滤器执行顺序
请求进入网关会碰到三类过滤器:路由过滤器、DefaultFilter、GlobalFilter
请求路由后,会将当前路由过滤器和DefaultFilter、GlobalFilter,合并到一个过滤器链(集合)中,排序后依次执行每个过滤器
每一个过滤器都必须指定一个int类型的order值,order值越小,优先级越高,执行顺序越靠前:
(1)GlobalFilter通过实现Ordered接口,或者添加@Order注解来指定order值,由我们自己指定
(2)路由过滤器和defaultFilter的order由Spring指定,默认是按照声明顺序从1递增
(3)当过滤器的order值一样时,会按照 defaultFilter > 路由过滤器 > GlobalFilter的顺序执行
6、跨域处理
跨域:域名不一致就是跨域,主要包括:
域名不同: www.taobao.com 和 www.taobao.org
域名相同,端口不同:localhost:8080和localhost8081
跨域问题:浏览器禁止请求的发起者与服务端发生跨域ajax请求,请求被浏览器拦截的问题
解决方案:CORS
globalcors: #全局跨域处理
add-to-simple-url-handler-mapping: true #解决option请求被拦截问题
cors-configurations:
'[/**]':
allowedOrigins: #允许哪些网站的跨域请求
- "http://localhost:8090"
allowedMethods: #允许的跨域ajax的请求方式
- "GET"
- "POST"
- "DELETE"
- "PUT"
- "OPTIONS"
allowedHeaders: "*" #允许在请求中携带的头信息
allowCredentials: true #是否允许携带cookie
maxAge: 360000 #这次跨域检测的有效期