0.序
在微服务架构中作为各个单元间的通讯。

1. 基本规则
Route(路由):这是网关的基本构建块。它由一个 ID,一个目标URI,一组断
言和一组过滤器定义。如果断言为真,则路由匹配。
Predicate(断言):输入类型是一个 ServerWebExchange。我们可以使用它
来匹配来自HTTP 请求的任何内容,例如 headers 或参数。
过滤器( filter), Gateway中的Filter 分为两种类型的Filter, 分别是Gateway
Filter和Global Filter。过滤器Filter 将会对请求和响应进行修改处理
2.maven
在gateway服务中添加maven依赖即可

1 2 3 4 5 6 7 8 9
| <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-loadbalancer</artifactId> </dependency>
|
3. 规则分发
所有的前端请求发送到gateway后网关会判断请求路径进行服务分发
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| server: port: 9998 spring: redis: timeout: 5000 host: port: 6379 password: cloud: gateway: globalcors: cors-configurations: '[/**]': allowedOrigins: "*" allowedMethods: [GET, POST, PUT, DELETE] discovery: locator: enabled: true routes: - id: user-service uri: lb://user-service predicates: - Path=/user/** - id: paper-service uri: lb://paper-service predicates: - Path=/paper/**,/exam/** config: redisTimeout: 60
|
4. 自定义拦截
当我们需要对所有的请求进行判断是否正常时,可以使用到拦截器,拦截没有登录的用户返回401等等请求告诉前端没有登陆,这里拦截所有没有带token请求头的对象并返回未登录
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113
| package org.kangdd.config;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.cloud.gateway.filter.GatewayFilterChain; import org.springframework.cloud.gateway.filter.GlobalFilter; import org.springframework.core.Ordered; import org.kangdd.util.JwtUtil; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.http.server.reactive.ServerHttpResponse; import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Mono; import org.springframework.data.redis.core.RedisTemplate;
import java.util.Map; import java.util.concurrent.TimeUnit;
@Component public class GlobalFilterConfig implements GlobalFilter, Ordered { @Value("${config.redisTimeout}") private Long redisTimeout;
@Autowired private RedisTemplate redisTemplate;
private static final String HEADER_NAME = "Access-Token"; @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { System.out.println("============过滤器============");
ServerHttpRequest request = exchange.getRequest(); ServerHttpResponse response = exchange.getResponse(); String url = request.getURI().getPath(); String token = request.getHeaders().getFirst(HEADER_NAME);
System.out.println("请求URL: " + url); System.out.println("获取到的token: " + token);
if (this.shouldNotFilter(url)) { return chain.filter(exchange); }
if (StringUtils.isEmpty(token)) { System.out.println("token为空"); return unAuthorize(exchange); }
Boolean tokenExists = redisTemplate.hasKey(token); if (tokenExists == null || !tokenExists) { System.out.println("Redis中不存在该token: " + token); return unAuthorize(exchange); }
boolean expireSuccess = redisTemplate.expire(token, redisTimeout, TimeUnit.SECONDS); if (!expireSuccess) { System.out.println("刷新token过期时间失败: " + token); } String userIdStr = String.valueOf(JwtUtil.parseUserIdFromToken(token)); Integer userId = Integer.parseInt(userIdStr); System.out.println("============登录用户id:" + userId + "============");
ServerHttpRequest newRequest = request.mutate().header(HEADER_NAME, token).build(); ServerWebExchange newExchange = exchange.mutate().request(newRequest).build(); return chain.filter(newExchange); }
@Override public int getOrder() { return 0; }
private Mono<Void> unAuthorize(ServerWebExchange exchange) { exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED); exchange.getResponse().getHeaders().setContentType(MediaType.APPLICATION_JSON); String errorMsg = "{\"error\": \"" + "用户未登录或登录超时,请重新登录" + "\"}"; return exchange.getResponse() .writeWith(Mono.just(exchange.getResponse().bufferFactory().wrap(errorMsg.getBytes()))); }
private boolean shouldNotFilter(String url) { if (url.startsWith("/user/login")) { return true; }
return false; }
}
|

5.注意
| 依赖 |
版本 |
| JDK |
11 |
| Maven |
2.7.18 |
| spring-cloud-alibaba.version |
2021.0.5.0 |
| spring-cloud.version |
2021.0.9 |
| spring-boot.version |
2.7.18 |