一、网关路由
1.1.认识网关
网关就是网络的关口。数据在网络间传输,从一个网络传输到另一网络时就需要经过网关来做数据的路由****和转发以及数据安全的校验。前端请求不能直接访问微服务,而是要请求网关:
- 网关可以做安全控制,也就是登录身份校验,校验通过才放行
- 通过认证后,网关再根据请求判断应该访问哪个微服务,将请求转发过去
1.2.快速入门
1.2.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>
1.2.2.配置路由
server:
port: 8080
spring:
application:
name: gateway
cloud:
nacos:
server-addr: 192.168.150.101: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:建议和微服务名保持一致
uri:路由目标
lb:负载均衡 ://服务名称
predicates:路由断言
- Path:以路径做匹配
二、网关登录校验
2.1.Gateway工作原理
- 客户端请求进入网关后由
HandlerMapping
对请求做判断,找到与当前请求匹配的路由规则(**Route
**),然后将请求交给WebHandler
去处理。 WebHandler
则会加载当前路由下需要执行的过滤器链(Filter chain
),然后按照顺序逐一执行过滤器(后面称为Filter
)。- 图中
Filter
被虚线分为左右两部分,是因为Filter
内部的逻辑分为pre
和post
两部分,分别会在请求路由到微服务之前和之后被执行。 - 只有所有
Filter
的pre
逻辑都依次顺序执行通过后,请求才会被路由到微服务。 - 微服务返回结果后,再倒序执行
Filter
的post
逻辑。 - 最终把响应结果返回。
2.2.自定义过滤器
网关过滤器链中的过滤器有两种:
- **
GatewayFilter
**:路由过滤器,作用范围比较灵活,可以是任意指定的路由Route
. - **
GlobalFilter
**:全局过滤器,作用范围是所有路由,不可配置。
2.3.登录校验
自定义GlobalFilter完成登录校验
自定义登录校验过滤器
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
//1、获取请求头
ServerHttpRequest request = exchange.getRequest();
//2.判断是否不需要拦截
if (isExclude(request.getPath().toString())) {
return chain.filter(exchange);
}
//3.获取token
List<String> headers = request.getHeaders().get("authorization");
String token = null;
if (headers != null && !headers.isEmpty()) {
token = headers.get(0);
}
//4.解析校验token
Long userId = null;
try {
userId = jwtTool.parseToken(token);
} catch (UnauthorizedException e) {
//拦截,设置响应状态码
ServerHttpResponse response = exchange.getResponse();
response.setRawStatusCode(401);
return response.setComplete();
}
//System.out.println("userId = " + userId);
//保存用户到请求头
String userInfo = userId.toString();
ServerWebExchange swe = exchange.mutate().//mutate 对下游请求做更改
request(builder -> builder.header("user-info", userInfo))
.build();
//6.放行
return chain.filter(swe);
}
2.4.微服务获取用户
2.4.1.保存用户信息到请求头
//保存用户到请求头
String userInfo = userId.toString();
ServerWebExchange swe = exchange.mutate().//mutate 对下游请求做更改
request(builder -> builder.header("user-info", userInfo))
.build();
2.4.2.拦截器获取用户
/**
* 拦截器,获取用户保存到ThreadLocal
*/
public class UserInfoInterceptor implements HandlerInterceptor {
//在controller执行之前运行
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
//1.获取用户信息
String userInfo = request.getHeader("user-info");
//2.将用户信息保存到ThreadLocal
if (StrUtil.isNotBlank(userInfo)) {
UserContext.setUser(Long.valueOf(userInfo));
}
//3.放行,只获取用户信息,不做拦截
return true;
}
//清理用户
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
UserContext.removeUser();
}
}
配置拦截器
@Configuration
@ConditionalOnClass(DispatcherServlet.class)
public class MvcConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new UserInfoInterceptor());
}
}
不过,需要注意的是,这个配置类默认是不会生效的,因为它所在的包是
com.hmall.common.config
,与其它微服务的扫描包不一致,无法被扫描到,因此无法生效。
基于SpringBoot的自动装配原理,我们要将其添加到
resources
目录下的
META-INF/spring.factories
文件中:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.hmall.common.config.MyBatisConfig,\
com.hmall.common.config.MvcConfig
2.5.OpenFeign传递用户
利用
RequestTemplate
类来添加请求头,将用户信息保存到请求头中。这样以来,每次OpenFeign发起请求的时候都会调用该方法,传递用户信息。
@Bean
public RequestInterceptor UserInfoRequestInterceptor() {
return requestTemplate -> {
Long userId = UserContext.getUser();
if (userId != null) {
requestTemplate.header("user-info", userId.toString());
}
};
}
三、配置管理
3.1.配置共享
我们可以把微服务共享的配置抽取到Nacos中统一管理,这样就不需要每个微服务都重复配置了。分为两步:
- 在Nacos中添加共享配置
- 微服务拉取配置
3.2.拉取配置共享
3.2.1.引入依赖
<!--nacos配置管理-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<!--读取bootstrap文件-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>
3.2.2.创建bootstrap.yaml
spring:
application:
name: cart-service # 服务名称
profiles:
active: dev
cloud:
nacos:
server-addr: 192.168.150.101 # nacos地址
config:
file-extension: yaml # 文件后缀名
shared-configs: # 共享配置
- dataId: shared-jdbc.yaml # 共享mybatis配置
- dataId: shared-log.yaml # 共享日志配置
- dataId: shared-swagger.yaml # 共享日志配置
3.3.配置热更新
3.3.1.添加配置到Nacos
dataId格式:
[服务名]-[spring.active.profile].[后缀名]
文件名称由三部分组成:
- **
服务名
**:购物车服务,所以是cart-service
- **
spring.active.profile
**:就是spring boot中的spring.active.profile
,可以省略,则所有profile共享该配置 - **
后缀名
**:例如yaml
3.3.2.配置热更新
创建属性读取类
@Data
@Component
@ConfigurationProperties(prefix = "hm.cart")
public class CartProperties {
private Integer maxAmount;
}
3.4.动态路由
四、总结
版权归原作者 柒末雪丶温存 所有, 如有侵权,请联系我们删除。