1、身份验证和权限校验
2、服务路由、负载均衡
3、请求限流
在SpringCloud中网关的实现包括两种
1、gateway
2、zuul
Zuul是基于Servlet实现的,属于堵塞式编程。而SpringCloudGateway则是基于Spring5中提供的WebFlux,属于响应式编程的实现,具有更好的性能
1、创建新的模块,引入SpirngCloudGateway的依赖和Nacos的服务发现依赖
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-gatewayartifactId>
dependency>
2、由于网关本身也是一个服务所以需要main函数来启动
@SpringBootApplication
public class GatewayApplication{
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class, args);
}
}
3、在网关中配置请求的路由
server:
port: 10084 #网关端口
spring:
application:
name: gateway #服务名称
cloud:
nacos:
discovery:
server-addr: localhost:8848 #nacos地址
gateway:
routes:
- id: user-service #路由ID,自定义只要唯一即可
# uri: http://localhost:8081 #路由地址http是固定的地址
uri: lb://userservice #路由的目标地址,lb就是负载均衡,后面就是服务名
predicates: #路由断言,也就是判断请求是否符合路由规则条件
- Path=/user/** #这个就是按照路径匹配,只要以/user开头就符合要求
- id: order-service
uri: lb://orderservice
predicates:
- Path=/order/**
网关路由可以配置的内容包括
1、路由ID:路由的唯一标识
2、uri:路由的目的地,也支持lb和http两种
3、predicates:路由断言,判断请求是否符合要求,符合则转发到路由目的地
4、filters:路由过滤器,处理请求或响应
我们在配置文件中写的断言规则只是字符串,这些字符串会被Predicate Factory读取并处理,转变成路由判断的条件
例如Path=/user/**是按照路径匹配,这个规则是由PathRoutePredicateFactory类来处理的
在Spring中提供了11种基本的Predicate工厂:
名称 | 说明 | 示例 |
---|---|---|
After | 是某个时间点后的请求 | - After=2037-01-20T17:42:47.789-07:00[America/Denver] |
Before | 是某个时间点之前的请求 | - Before=2031-04-13T15:14:47.433+08:00[Asia/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-Id,\d+ |
Host | 请求必须是访问某个host(域名) | - Host=***.somehost.org,**.anotherhost.org |
Method | 请求方式必须指定方式 | - Method=GET,POST |
Path | 请求路径必须符合指定规则 | - Path=/red/** |
Query | 请求参数必须包含指定参数 | - Query=name,Jack或者- Query=name |
RemoteAddr | 请求者的ip必须在指定范围内 | - RemoteAddr=192.168.1.1/24 |
Weight | 权重处理 |
官方配置示例
GatewayFilter是网关中提供的一种过滤器,可以对进入网关的请求和微服务返回的响应做处理
Spring提供了31种路由过滤器工厂.例如:
名称 | 说明 |
---|---|
AddRequestHeader | 给当前请求添加一个请求头 |
RemoveRequestHeader | 移除请求中的一个请求头 |
AddResponseHeader | 给响应结果中添加一个响应头 |
RemoveResponseHeader | 从响应结果中移除有一个响应头 |
RequestRateLimiter | 限制请求的流量 |
… | … |
官方实例
给所有进入userservice的请求添加一个请求头:Truth=itcast is freaking awesome !
实现方式:在gateway中修改application.yml文件,给userservice的路由添加过滤器
server:
port: 10084 #网关端口
spring:
application:
name: gateway #服务名称
cloud:
nacos:
discovery:
server-addr: localhost:8848 #nacos地址
gateway:
routes:
- id: user-service #路由ID,自定义只要唯一即可
# uri: http://localhost:8081 #路由地址http是固定的地址
uri: lb://userservice #路由的目标地址,lb就是负载均衡,后面就是服务名
predicates: #路由断言,也就是判断请求是否符合路由规则条件
- Path=/user/** #这个就是按照路径匹配,只要以/user开头就符合要求
filters:
- AddRequestHeader=Truth, Itcast is freaking awesome ! #添加请求头
- id: order-service
uri: lb://orderservice
predicates:
- Path=/order/**
在业务代码中,通过 @RequestHeader获取,这只是在userservice中生效
@GetMapping("/{id}")
public User queryById(@PathVariable("id") Long id, @RequestHeader(value="Truth", required = false) String truth) {
System.out.println("RequestHeader Truth " + truth);
return userService.queryById(id);
}
给全部微服务的请求添加请求头,在gateway中修改application.yml文件
server:
port: 10084 #网关端口
spring:
application:
name: gateway #服务名称
cloud:
nacos:
discovery:
server-addr: localhost:8848 #nacos地址
gateway:
routes:
- id: user-service #路由ID,自定义只要唯一即可
# uri: http://localhost:8081 #路由地址http是固定的地址
uri: lb://userservice #路由的目标地址,lb就是负载均衡,后面就是服务名
predicates: #路由断言,也就是判断请求是否符合路由规则条件
- Path=/user/** #这个就是按照路径匹配,只要以/user开头就符合要求
- id: order-service
uri: lb://orderservice
predicates:
- Path=/order/**
default-filters:
- AddRequestHeader=Truth, Itcast is freaking awesome ! #添加请求头
全局过滤器的作用是处理一切进入网关的请求和微服务响应,与GatewayFilter的作用一样
区别在于GateFilter通过配置定义,处理逻辑规定的,而GlobalFilter的逻辑需要自己写代码实现
定义方式是实现GlobalFilter接口
public interface GlobalFilter {
/**
*处理当前请求,有必要的话通过GatewayFilterChain将请求交给下一个过滤器处理
* @param exchange 请求上下文,里面可以获取request,response等信息
* @param chain 用来把请求委托给下一个过滤器
* */
Mono<Void> filter(ServerWebExchage exchange, GatewayFilterChain chain);
}
定义过滤器,拦截请求,判断请求的参数是否满足下面条件
参数中是否有authorization
authorization参数值是否为admin
如果同时满足就放行
/**
* @Order设置过滤器的优先级
* 数值越小优先级越高
*/
@Order(-1)
@Component
public class AuthorizationFilter implements GlobalFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 获取请求参数, 通过上下文获取请求
ServerHttpRequest request = exchange.getRequest();
MultiValueMap<String, String> map = request.getQueryParams();
// 获取参数中的authorization
String auth = map.getFirst("authorization");
// 判断参数值是否为admin
if ("admin".equals(auth)) {
// 发行
return chain.filter(exchange);
}
// 除了拦截外,还需要设置状态码,这样用户体验感知强
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
// 拦截
return exchange.getResponse().setComplete();
}
}
请求进入网关会碰到三类过滤器:当前路由的过滤器、DefaultFilter、GlobalFilter
请求路由后,会将当前路由过滤器和DefaultFilter、GlobalFilter合并到一个过滤器链(集合)中,排序后依次执行每个过滤器
每一个过滤器都必须实现指定一个int类型的Order值,order值越小,优先级越高,执行顺序越靠前
GlobalFilter通过实现Order接口,或者添加@Order注解来指定order值
路由过滤器和defaultFilter的order由Spring指定,默认是按照声明顺序从1递增
当过滤器的order值一致时,会按照defaultFilter>路由过滤器>GlobalFilter的顺序执行
跨域:域名不一致就是跨域,主要包括
1、域名不同:www.taobao.com和www.taobao.org
2、域名相同,端口不一致
跨域问题:浏览器禁止请求的发起者与服务端发生跨域ajax请求,请求被浏览器拦截的问题
gateway处理跨域采用的是cors方案,并且只需要简单配置即可实现
spring:
application:
name: gateway #服务名称
cloud:
nacos:
discovery:
server-addr: localhost:8848 #nacos地址
gateway:
globalcors:
add-to-simple-url-handler-mapping: true
cors-configurations:
'[/**]': #拦截的请求
allowedOrigins: #允许跨域的请求
- "http://localhost:8080"
allowedMethods: #运行跨域的请求方式
- "GET"
- "POST"
- "DELETE"
- "PUT"
- "OPTIONS"
allowedHeaders: "*" #允许请求中携带的头信息
allowedCredentials: true #是否允许携带cookie
maxAge: 36000 #跨域检测的有效期,单位s