6.1 网关的作用
- 对用户请求做身份认证、权限校验
- 将用户请求路由到微服务,并实现负载均衡
- 对用户请求做限流
6.2 搭建网关服务步骤
创建一个新的模块作为网关系统,在 pom.xml 中引入 SpringCloudGateway 的依赖,同时还要引入 nacos 的服务发现依赖
<!--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>
在application.yml配置文件中编写路由配置及nacos地址
server:
port: 10010
spring:
application:
name: gateway
cloud:
nacos:
server-addr: localhost:8848 # nacos地址
gateway:
routes: # 网关路由配置
- id: user-service # 路由标识,必须唯一
uri: lb://user-service # 路由的目标地址,lb就是负载均衡,后面跟服务名称
predicates: # 路由断言,判断请求是否符合规则
- Path=/user/** # 路径匹配,判断路径是否是以/user/开头,如果是则符合
- id: order-service
uri: lb://order-service
predicates:
- Path=/order/**
大致流程:
路由配置大致包括:
- 路由id:路由的唯一标识
- 路由目标(uri):路由的目标地址,http代表固定地址,lb代表根据服务名负载均衡
- 路由断言(predicates):判断路由的规则
- 路由过滤器(filters):对请求或响应做处理
6.3 路由断言工厂(路由匹配规则)
我们在配置文件中写的断言规则只是字符串,这些字符串会被Predicate Factory 读取并处理,转变为路由判断的条件
例如 Path=/user/** 是按照路径匹配,这个规则是由 PathRoutePredicateFactory 类来处理的
具体规则的使用,可以参考Spring官网 https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#gateway-request-predicates-factories
6.4 路由过滤器
GatewayFilter 是网关中提供的一种过滤器,可以对进入网关的请求和微服务返回的响应做处理
Spring提供了30多种过滤器:
-
AddRequestHeader:此列表将 X-Request-red:blue 添加到所有匹配请求的下游请求头
spring: cloud: gateway: routes: - id: add_request_header_route uri: https://example.org # 过滤器 filters: - AddRequestHeader=X-Request-red, blue
-
AddRequestParameter:为所有匹配请求的下游请求的地址添加请求参数 /?red=blue
spring: cloud: gateway: routes: - id: add_request_parameter_route uri: https://example.org filters: - AddRequestParameter=red, blue
-
AddResponseHeader:此列表将 X-Request-red:blue 添加到所有匹配请求的下游请求头
spring: cloud: gateway: routes: - id: add_response_header_route uri: https://example.org filters: - AddResponseHeader=X-Response-Red, Blue
-
PrefixPath:将 /mypath 作为前缀添加到路径,所以例如 /hello 的路径将会变为 /mypath/hello
spring: cloud: gateway: routes: - id: prefixpath_route uri: https://example.org filters: - PrefixPath=/mypath
-
RemoveRequestHeader:在将 X-Request-Foo 标头发送到下游之前将其删除
spring: cloud: gateway: routes: - id: removerequestheader_route uri: https://example.org filters: - RemoveRequestHeader=X-Request-Foo
-
RemoveResponseHeader:在将 X-Response-Foo 头返回到网关客户端之前从响应中删除该头
spring: cloud: gateway: routes: - id: removeresponseheader_route uri: https://example.org filters: - RemoveResponseHeader=X-Response-Foo
-
RemoveRequestParameter:在向下游发送之前删除 red 参数
spring: cloud: gateway: routes: - id: removerequestparameter_route uri: https://example.org filters: - RemoveRequestParameter=red
部分过滤器中参数可以用变量来代替,可以解析出匹配路径或主机的URI变量
例如:
spring:
cloud:
gateway:
routes:
- id: add_request_header_route
uri: https://example.org
predicates:
- Path=/red/{segment}
filters:
- AddRequestHeader=X-Request-Red, Blue-{segment}
具体可以看Spring官网:https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#gatewayfilter-factories
默认过滤器 - default-filters
可以对所有路由都生效,而不是针对单个路由
spring:
application:
name: gateway
cloud:
nacos:
server-addr: localhost:8848 # nacos地址
gateway:
routes: # 网关路由配置
- id: user-service # 路由标识,必须唯一
uri: lb://user-service # 路由的目标地址,lb就是负载均衡,后面跟服务名称
predicates: # 路由断言,判断请求是否符合规则
- Path=/user/** # 路径匹配,判断路径是否是以/user/开头,如果是则符合
filters:
# 添加请求参数
- AddRequestParameter=red, blue
# 添加请求头
- AddRequestHeader=X-Request-red, blue
- id: order-service
uri: lb://order-service
predicates:
- Path=/order/**
# 默认过滤器
default-filters:
# 添加响应头
- AddResponseHeader=X-Response-Red, Blue
6.5 全局过滤器 - GlobalFilter
全局过滤器的作用也是处理一切进入网关的请求和微服务响应,与路由过滤器的作用一样。
区别在于路由过滤器通过配置定义,处理逻辑是固定的。而全局过滤器的逻辑需要自己写代码实现,所以可以处理更为复杂的过滤。
定义方式:创建一个拦截器实现 GlobalFilter 接口
例子:判断请求参数是否携带authorization参数,携带放行,否则拦截
// 顺序注解,和实现Ordered接口效果相同
// @Order(-1)
@Component
public class AuthorizeFilter implements GlobalFilter, Ordered {
/**
* 处理当前请求,有必要的话通过{@link GatewayFilterChain} 将请求交给下一个过滤器处理
* @param exchange 请求上下文,里面可以获取 Request、Response等信息
* @param chain 用来把请求委托给下一个过滤器
* @return {@code Mono<Void>} 返回表示当前过滤器业务结束
*/
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 1. 获取请求参数
ServerHttpRequest request = exchange.getRequest();
MultiValueMap<String, String> params = request.getQueryParams();
// 2. 获取参数中的 authorization 参数
String auth = params.getFirst("authorization");
// 3. 判断参数值是否存在
if (auth != null && auth != "") {
// 4. 是,放行
return chain.filter(exchange);
}
// 5. 否,拦截
// 5.1. 设置状态码
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
// 5.2 拦截请求
return exchange.getResponse().setComplete();
}
/**
* 该过滤器的优先级,越小优先级越高
* @return int级别
*/
@Override
public int getOrder() {
return -1;
}
}
6.6 过滤器链执行顺序
请求进入网关会碰到三类过滤器:当前路由的过滤器(具体服务下)、DefaultFilter(默认过滤器)、GlobalFilter(全局过滤器)
请求路由后,会将当前路由过滤器和DefaultFilter、GlobalFilter,合并到一个过滤器链(集合)中,排序后依次执行每个过滤器
具体顺序:
- 每一个过滤器都必须指定一个 int 类型的 order 值,order值越小,优先级越高,执行顺序越靠前
- GlobalFilter 通过实现 Ordered 接口,或者添加 @Order 注解来指定 order 值,自己设定
- 路由过滤器 和 DefaultFilter 的 order 由 Spring 指定,默认是按照声明顺序从 1 递增
- 当过滤器的 order 值一样时,会按照 DefaultFilter > 路由过滤器 > GlobalFilter 的顺序执行
6.7 网关的cors跨域配置
跨域问题:
当发起者与服务端所在域不一致时就是跨域,其中 协议、域名、端口,有一样不同则视为跨域,而当前后端分离,前端用ajax发起请求到后端时,此时因为域的不同浏览器会拦截该请求
解决方案:CORS
即在前端发起ajax请求进行跨域访问服务端时,浏览器先会询问服务端是否允许请求者的访问,服务端会给浏览器一个通行证使浏览器放行该请求
具体配置
spring:
cloud:
gateway:
globalcors: # 全局跨域处理
# 浏览器会先询问是否允许跨域,该配置使浏览器cors询问options正常发起
add-to-simple-url-handler-mapping: true
cors-configurations:
'[/**]':
allowedOrigins: # 允许哪些网站的跨域请求
- "http://localhost:8090"
- "http://www.leyou.com"
allowedMethods: # 允许的跨域ajax的请求方式
- "GET"
- "POST"
- "DELETE"
- "PUT"
- "OPTIONS"
allowedHeaders: # 允许在请求中携带的头信息
- "*"
allowCredentials: true # 是否允许携带Cookie
# 减少cors询问损耗,在有效期内浏览器将不会重复询问是否允许跨域
maxAge: 360000