SrpingCloud网关的作用
我们知道前端发送请求到后端才能获取到数据再渲染到前端页面上去,但是微服务在不同的服务器端口上那么前端有没有一种简便的方法只用向后端的一个端口发送请求,就像springboot项目那样呢?有的,兄弟有的,这样的方法当然不止一种了。着重介绍一下SrpingCloud的网关。网关的一个很重要的作用就是对请求进行转发。
使用SrpingCloud网关进行请求路由
首先网关也可以看做是一个微服务,这个微服务一个重要的作用就是就是将前端发送过来的请求转发到各个微服务中。
1、首先引入相关依赖
<!--网关-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!--nacos discovery-->
<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-loadbalancer</artifactId>
</dependency>
</dependencies>
2、编写启动类
ackage com.hmall.gateway;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class, args);
}
}
3、编写配置文件
server:
port: 8080
spring:
application:
name: gateway
cloud:
nacos:
server-addr: 192.168.150.129:8848
gateway:
routes:
- id: item-service # 路由规则id,自定义,唯一
uri: lb://item-service # 路由的目标服务,lb代表负载均衡,会从注册中心拉取服务列表
predicates: # 路由断言,判断当前请求是否符合当前规则,符合则路由到目标服务
- Path=/items/**,/search/**
- id: cart-service
uri: lb://cart-service
predicates:
- Path=/carts/**
- id: user-service
uri: lb://user-service
predicates:
- Path=/users/**,Path=/addresses/**
- id: trade-service
uri: lb://trade-service
predicates:
- Path=/trade/**
- id: pay-service
uri: lb://pay-service
predicates:
- Path=/pay/**
#注: - Path=/items/**
- Path=/items/**,/search/**
这样编写配置文件是错误的,这样默认要求两个都要满足,但是不可能同时满足这两种路由断言
这样就可以实现前端向后端8080端口发送请求,然后再又网关对请求进行转发
SrpingCloud网关的其他属性
filters是对请求进行过滤的属性,也是比较常用的属性,这里列举一些常用的过滤器

网关实现登录校验
要做登录校验我们需要拦截所有的请求来校验用户是否已经登录,你们上面的路由过滤器就不太够用了,我们需要使用全局过滤器来实现对所有路由进行过滤。
GlobalFilter:全局过滤器,作用范围是所有路由;声明后自动生效。

exchange对象就有我们所需要的用于做登录校验的数据,这里先模拟登录校验的逻辑,待会会将逻辑进行补全
public class MyGlobalFilter implements GlobalFilter , Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
//TODO 模拟登录校验
ServerHttpRequest request = exchange.getRequest();
HttpHeaders headers = request.getHeaders();
System.out.println(headers);
//将数据传递给下一个过滤器
return chain.filter(exchange);
}
@Override
public int getOrder() {
return 0;
}
}
看完这个示例我们就可以写一个登录校验的拦截器了
@Component
@RequiredArgsConstructor
public class AuthGlobalFilter implements GlobalFilter , Ordered {
//解析jwt的类
private final JwtTool jwtTool;
//存放需要拦截路径和不需要拦截路径的配置类
private final AuthProperties authProperties;
//springcloud自带的路径匹配类
private final AntPathMatcher antPathMatcher = new AntPathMatcher();
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
//获取到请求体
ServerHttpRequest request = exchange.getRequest();
//判断是否放行
if(isExclude(request.getPath().toString()))
{
//放行
return chain.filter(exchange);
}
//获取token
HttpHeaders headers = request.getHeaders();
List<String> list = headers.get("authorization");
String token = "";
if(list != null && !list.isEmpty())
{
token = list.get(0);
}
//做登录校验
Long userId = null;
try{
userId = jwtTool.parseToken(token);
} catch (Exception e)
{
ServerHttpResponse response = exchange.getResponse();
response.setStatusCode(HttpStatus.UNAUTHORIZED);
response.setComplete();
}
//将数据传递给下一个微服务
System.out.println(userId);
//放行
return chain.filter(exchange);
}
private boolean isExclude(String path) {
List<String> excludePaths = authProperties.getExcludePaths();
for (String excludePath : excludePaths) {
if(antPathMatcher.match(excludePath, path))
{
return true;
}
}
return false;
}
@Override
public int getOrder() {
return 0;
}
}
然后我们补全一下网关传递给其他微服务的逻辑:我们可以将用户的信息放在请求头中,再由网关发送请求到各个微服务,微服务之间可以使用@ReuqstHeader的注解获取请求头,但是这样获取方式比较繁琐,我们可以定义一个MVC拦截器来处理请求但是不做拦截,只获取请求并且存到当前线程当中,这样后端微服务就可以获取到前端穿过来的用户信息
1、将请求存到请求头
//将数据传递给下一个微服务
String userinfo = userId.toString();
exchange.mutate()
.request(builder -> builder.header("userId", userinfo))
.build();
2、编写MVC拦截器
public class UserInfoInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 1.获取请求头中的用户信息
String userInfo = request.getHeader("user-info");
// 2.判断是否为空
if (StrUtil.isNotBlank(userInfo)) {
// 不为空,保存到ThreadLocal
UserContext.setUser(Long.valueOf(userInfo));
}
// 3.放行
return true;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
// 移除用户
UserContext.removeUser();
}
}
3、编写拦截器配置类
@Configuration
@ConditionalOnClass(DispatcherServlet.class)//网关也引用了common模块,网关不是基于SpringMVC,底层采用非阻塞式响应式编程是基于webflux,所以会有冲突,DispatcherServlet是SpringMVC的核心类所有用这个进行筛选
public class MvcConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new UserInfoInterceptor());
}
}
4、配置META-INF/spring.factories
不过,需要注意的是,这个配置类默认是不会生效的,因为它所在的包是com.hmall.common.config,与其它微服务的扫描包不一致,无法被扫描到,因此无法生效。
基于SpringBoot的自动装配原理,我们要将其添加到resources目录下的META-INF/spring.factories文件中:
com.hmall.common.config.MvcConfig
这样就可以实现网关传递用户信息给其他微服务

296

被折叠的 条评论
为什么被折叠?



