diff --git a/src/main/java/com/genersoft/iot/vmp/aiot/service/impl/AiScreenshotServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/aiot/service/impl/AiScreenshotServiceImpl.java index d8e4a224b..129f95539 100644 --- a/src/main/java/com/genersoft/iot/vmp/aiot/service/impl/AiScreenshotServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/aiot/service/impl/AiScreenshotServiceImpl.java @@ -13,6 +13,7 @@ import org.springframework.stereotype.Service; import org.springframework.web.client.RestTemplate; +import java.net.URI; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.HashMap; @@ -161,6 +162,14 @@ public class AiScreenshotServiceImpl implements IAiScreenshotService { return; } + // 先写 Redis 缓存,再唤醒等待线程(避免竞态:线程被唤醒后立即读缓存但缓存还没写入) + String cameraCode = (String) data.get("camera_code"); + String status = (String) data.get("status"); + if ("ok".equals(status) && cameraCode != null) { + String url = (String) data.get("url"); + writeCache(cameraCode, url); + } + CompletableFuture> future = pendingRequests.get(requestId); if (future != null) { future.complete(data); @@ -168,14 +177,6 @@ public class AiScreenshotServiceImpl implements IAiScreenshotService { } else { log.warn("[AI截图] 回调未找到对应请求(可能已超时): requestId={}", requestId); } - - // 写入 Redis 缓存(无论 future 是否存在,缓存都应更新) - String cameraCode = (String) data.get("camera_code"); - String status = (String) data.get("status"); - if ("ok".equals(status) && cameraCode != null) { - String url = (String) data.get("url"); - writeCache(cameraCode, url); - } } /** @@ -217,8 +218,9 @@ public class AiScreenshotServiceImpl implements IAiScreenshotService { return null; } + // 使用 URI.create 避免 RestTemplate 对已编码的预签名 URL 做二次编码 RestTemplate restTemplate = new RestTemplate(); - byte[] imageBytes = restTemplate.getForObject(cosUrl, byte[].class); + byte[] imageBytes = restTemplate.getForObject(URI.create(cosUrl), byte[].class); log.debug("[AI截图] 代理图片成功: cameraCode={}, size={}", cameraCode, imageBytes != null ? imageBytes.length : 0); return imageBytes; } catch (Exception e) {