From 2b702197fa2d6914584b47cd737d420ac06b16e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AD=99=E5=B0=8F=E4=BA=91?= Date: Mon, 2 Feb 2026 15:43:41 +0800 Subject: [PATCH] xx --- .../gateway/filter/WvpAccessTokenFilter.java | 124 ++++++++++++++---- 1 file changed, 96 insertions(+), 28 deletions(-) diff --git a/src/main/java/com/ruoyi/gateway/filter/WvpAccessTokenFilter.java b/src/main/java/com/ruoyi/gateway/filter/WvpAccessTokenFilter.java index ccbfe05..b00b093 100644 --- a/src/main/java/com/ruoyi/gateway/filter/WvpAccessTokenFilter.java +++ b/src/main/java/com/ruoyi/gateway/filter/WvpAccessTokenFilter.java @@ -5,11 +5,18 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.cloud.gateway.filter.GatewayFilter; import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory; -import org.springframework.http.server.reactive.ServerHttpRequest; +import org.springframework.core.io.buffer.DataBuffer; +import org.springframework.core.io.buffer.DataBufferFactory; +import org.springframework.http.HttpStatus; +import org.springframework.http.server.reactive.ServerHttpResponse; import org.springframework.stereotype.Component; +import org.springframework.web.reactive.function.client.WebClient; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Mono; +import java.nio.charset.StandardCharsets; +import java.time.LocalDateTime; + /** * WVP Access Token 过滤器 * 用于为 WVP 请求添加或替换 access-token 请求头 @@ -19,9 +26,22 @@ public class WvpAccessTokenFilter extends AbstractGatewayFilterFactory { - try { - // 获取 access token - String accessToken = getAccessToken(); + String path = exchange.getRequest().getURI().getPath(); + String query = exchange.getRequest().getURI().getQuery(); + String fullPath = query != null ? path + "?" + query : path; - log.info("WVP 请求 - 原始路径: {}", exchange.getRequest().getURI().getPath()); - log.info("WVP 请求 - 添加 access-token"); + log.info("WVP 请求 - 路径: {}", fullPath); - // 修改请求,添加或替换 access-token 请求头 - ServerHttpRequest modifiedRequest = exchange.getRequest().mutate() - .header("access-token", accessToken) - .build(); + // 使用 WebClient 直接调用 WVP,支持自动重试 + return callWvpWithRetry(fullPath, exchange, 0) + .flatMap(responseBody -> { + // 将响应写回客户端 + ServerHttpResponse response = exchange.getResponse(); + response.setStatusCode(HttpStatus.OK); + response.getHeaders().add("Content-Type", "application/json;charset=UTF-8"); - // 创建新的 exchange - ServerWebExchange modifiedExchange = exchange.mutate() - .request(modifiedRequest) - .build(); + DataBufferFactory bufferFactory = response.bufferFactory(); + DataBuffer buffer = bufferFactory.wrap(responseBody.getBytes(StandardCharsets.UTF_8)); - return chain.filter(modifiedExchange).then(Mono.fromRunnable(() -> { - log.info("WVP 响应 - Status: {}", modifiedExchange.getResponse().getStatusCode()); - })); - } catch (Exception e) { - log.error("获取 WVP access token 失败", e); - // 即使获取 token 失败,也继续转发请求 - return chain.filter(exchange); - } + return response.writeWith(Mono.just(buffer)); + }) + .onErrorResume(e -> { + log.error("WVP 请求失败", e); + return chain.filter(exchange); + }); }; } /** - * 获取 access token,使用缓存机制 - * 如果缓存为空,则调用 WvpTokenClient.login 获取新的 token + * 调用 WVP 接口,支持自动重试 + * + * @param path 请求路径 + * @param exchange ServerWebExchange + * @param retryCount 重试次数 + * @return 响应体 + */ + private Mono callWvpWithRetry(String path, ServerWebExchange exchange, int retryCount) { + try { + String accessToken = getAccessToken(); + String wvpUrl = "http://wvp-pro:18978" + path; + + log.debug("调用 WVP 接口: {}, access-token: {}", wvpUrl, accessToken); + + return webClient.get() + .uri(wvpUrl) + .header("access-token", accessToken) + .retrieve() + .bodyToMono(String.class) + .onErrorResume(e -> { + log.error("WVP 请求失败,尝试刷新 token 并重试", e); + if (retryCount < 1) { + // 清除缓存的 token,下次会重新获取 + clearCachedToken(); + // 重试一次 + return callWvpWithRetry(path, exchange, retryCount + 1); + } + return Mono.error(e); + }); + } catch (Exception e) { + log.error("获取 access token 失败", e); + return Mono.error(e); + } + } + + /** + * 获取 access token,使用缓存机制并支持提前刷新 + * 如果缓存为空或即将过期,则调用 WvpTokenClient.login 获取新的 token */ private String getAccessToken() throws Exception { - if (cachedAccessToken == null) { + LocalDateTime now = LocalDateTime.now(); + + // 检查 token 是否需要刷新(不存在或即将过期) + if (cachedAccessToken == null || tokenExpirationTime == null || + now.plusMinutes(REFRESH_BEFORE_EXPIRATION_MINUTES).isAfter(tokenExpirationTime)) { + synchronized (LOCK) { - if (cachedAccessToken == null) { - log.info("缓存中没有 access token,正在登录 WVP..."); + // 双重检查 + now = LocalDateTime.now(); + if (cachedAccessToken == null || tokenExpirationTime == null || + now.plusMinutes(REFRESH_BEFORE_EXPIRATION_MINUTES).isAfter(tokenExpirationTime)) { + + log.info("Token 不存在或即将过期,正在刷新 WVP access token..."); WvpTokenClient.LoginResponse loginResponse = WvpTokenClient.login("admin", "admin"); + if (loginResponse.getCode() == 0 && loginResponse.getData() != null) { cachedAccessToken = loginResponse.getData().getAccessToken(); - log.info("WVP 登录成功,获取到 access token"); + // 设置过期时间为当前时间 + TOKEN_EXPIRATION_MINUTES + tokenExpirationTime = now.plusMinutes(TOKEN_EXPIRATION_MINUTES); + log.info("WVP 登录成功,获取到 access token,过期时间: {}", tokenExpirationTime); } else { throw new Exception("WVP 登录失败: " + loginResponse.getMsg()); } } } } + return cachedAccessToken; } @@ -85,6 +152,7 @@ public class WvpAccessTokenFilter extends AbstractGatewayFilterFactory