fix(aiot): 修复截图代理两个bug:竞态条件+URL双重编码
1. handleCallback先写Redis缓存再complete Future, 避免等待线程被唤醒后读取缓存为空的竞态条件 2. RestTemplate使用URI.create()传入预签名URL, 避免对已编码的%3B等字符做二次编码导致COS 403 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -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<Map<String, Object>> 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) {
|
||||
|
||||
Reference in New Issue
Block a user