Gateway
目录
- Gateway
- 一、为什么需要网关
- 二、gateway入门
- 三、断言工厂
- 四、过滤器工厂
- 五、全局过滤
- 1. 实现
- 2. 过滤器执行顺序
- 六、跨域问题
一、为什么需要网关
不能让外部能够直接访问微服务,而是需要通过网关访问:
网关的作用:
- 身份认证和权限校验
- 请求路由,负载均衡
- 限流
二、gateway入门
搭建网关步骤:
-
创建新的模块,引入依赖:
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency>
-
配置nacos和路由
spring: cloud: nacos: server-addr: localhost:80 gateway: routes: - id: user-service # 路由id 必填 不重复即可 uri: lb://userService # 路由目标地址 predicates: # 路由断言,判断请求是否符合规则 - 'Path=/user/**' # 判断路径是否以/user开头,如果是则符合 - id: order-service uri: lb://orderService predicates: - 'Path=/order/**' application: name: gateway server: port: 10010
-
启动测试:
-
小结:
三、断言工厂
我们配置时候配置的路由断言就是由断言工厂解析的,我们配置的是字符串,路由工厂则取解析。
配一个after试试:
spring:
cloud:
nacos:
server-addr: localhost:80
gateway:
routes:
-
id: user-service # 路由id 必填 不重复即可
uri: lb://userService # 路由目标地址
predicates: # 路由断言,判断请求是否符合规则
- 'Path=/user/**' # 判断路径是否以/user开头,如果是则符合
-
id: order-service
uri: lb://orderService
predicates:
- 'Path=/order/**'
- After=2023-01-14T23:38:47.789+08:00[Asia/Shanghai]
application:
name: gateway
server:
port: 10010
改着玩,如果符合要求就能请求成功,如果不符合要求就404了。
四、过滤器工厂
可对进入网关的请求和服务的响应作处理。
局部配置:
spring:
cloud:
nacos:
server-addr: localhost:80
gateway:
routes:
-
id: user-service # 路由id 必填 不重复即可
uri: lb://userService # 路由目标地址
predicates: # 路由断言,判断请求是否符合规则
- 'Path=/user/**' # 判断路径是否以/user开头,如果是则符合
filters:
- AddRequestHeader=IHeader,this is filter
-
id: order-service
uri: lb://orderService
predicates:
- 'Path=/order/**'
- After=2023-01-14T23:40:00+08:00[Asia/Shanghai]
application:
name: gateway
server:
port: 10010
修改user-service的代码:
@GetMapping("/{id}")
public User queryById(@PathVariable("id") Long id,
@RequestHeader(value = "IHeader", required = false) String IHeader) {
System.out.println(IHeader);
return userService.queryById(id);
}
访问user-service的接口即可看到打印 this is filter
全局配置:
spring:
cloud:
nacos:
server-addr: localhost:80
gateway:
routes:
-
id: user-service # 路由id 必填 不重复即可
uri: lb://userService # 路由目标地址
predicates: # 路由断言,判断请求是否符合规则
- 'Path=/user/**' # 判断路径是否以/user开头,如果是则符合
-
id: order-service
uri: lb://orderService
predicates:
- 'Path=/order/**'
- After=2023-01-14T23:40:00+08:00[Asia/Shanghai]
default-filters:
- AddRequestHeader=IHeader,this is filter
application:
name: gateway
server:
port: 10010
访问user-service的接口即可看到打印 this is filter
五、全局过滤
1. 实现
和上一种配置的过滤器一样,区别在于全局过滤器可以自定义逻辑。
实现GlobalFilter接口即可(有web Flux的感觉)
public class IFilter implements GlobalFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
return null;
}
}
例子:
// 过滤器链上的优先级 越低优先级越高
@Order(-1)
@Component
public class IFilter implements GlobalFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 1.获取请求参数
ServerHttpRequest request = exchange.getRequest();
MultiValueMap<String, String> queryParams = request.getQueryParams();
// 2.获取某个参数
String auth = queryParams.getFirst("username");
// 3.业务
if ("admin".equals(auth)) {
// 放行
return chain.filter(exchange);
}
// 修改返回状态码
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
// 拦截
return exchange.getResponse().setComplete();
}
}
这里有个小坑:
如果这个全局过滤器没有放在和启动类同包下,那么无法被扫描,也就无法生效,解决方案也很简单:
- 放在和启动类同包下
- 使用@ComponentScan、@Import等注解,将其导入IOC容器中。
2. 过滤器执行顺序
不管是yml中配置的filters、default-filters还是GlobalFilter,其本质都是GatewayFilter。
所以他们的执行顺序是由他们的order值决定,他们的order值有以下规则:
- 路由过滤器和默认过滤器的order由spring指定,默认是按照声明顺序从1递增
- GlobalFilter的Order值由我们决定
- 当过滤器的order值相同时,会按照defaultFilter > 路由过滤器 > GlobalFilter的顺序执行
六、跨域问题
经典问题,配置解决即可
spring:
cloud:
gateway:
globalcors:
corsConfigurations:
'[/**]':
# 允许跨域的源(网站域名/ip),设置*为全部
allowedOrigins: "*"
# 允许跨域的method, 默认为GET和OPTIONS,设置*为全部
allowedMethods: "*"
# 允许跨域请求里的head字段,设置*为全部
allowedHeaders: "*"
allowCredentials: true # 是否允许携带cookie
maxAge: 360000 # 本次跨域有效期
allowedOrigins: "*"
# 允许跨域的method, 默认为GET和OPTIONS,设置*为全部
allowedMethods: "*"
# 允许跨域请求里的head字段,设置*为全部
allowedHeaders: "*"
allowCredentials: true # 是否允许携带cookie
maxAge: 360000 # 本次跨域有效期