fix(update): use curl for Xiaomi APK upload to bypass server-side body timeout
RestTemplate drops large multipart payloads on the MI API server; switching to ProcessBuilder curl with Expect:100-continue headers and a 130-minute timeout resolves upload failures for large APKs. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
这个提交包含在:
父节点
afb57a5d5f
当前提交
e7dbdc2ef3
@ -974,18 +974,30 @@ public class StoreSubmissionService {
|
|||||||
Map.of("name", "apk", "hash", md5Hex(apkFile))
|
Map.of("name", "apk", "hash", md5Hex(apkFile))
|
||||||
));
|
));
|
||||||
|
|
||||||
HttpHeaders headers = new HttpHeaders();
|
// Use curl ProcessBuilder: MI API server drops large multipart body with RestTemplate.
|
||||||
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
|
// curl sends Expect:100-continue which bypasses the server-side body timeout.
|
||||||
MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
|
String requestDataJson = asJsonString(requestData);
|
||||||
body.add("apk", new FileSystemResource(apkFile));
|
String sigJson = rsaEncryptHexChunked(asJsonString(sig), publicKey);
|
||||||
body.add("RequestData", asJsonString(requestData));
|
ProcessBuilder pb = new ProcessBuilder(
|
||||||
body.add("SIG", rsaEncryptHexChunked(asJsonString(sig), publicKey));
|
"curl", "-s", "--connect-timeout", "30",
|
||||||
|
"--max-time", String.valueOf(130 * 60),
|
||||||
ResponseEntity<String> response = rest.postForEntity(
|
"-F", "apk=@" + apkFile.getAbsolutePath(),
|
||||||
"https://api.developer.xiaomi.com/devupload/dev/push",
|
"-F", "RequestData=" + requestDataJson,
|
||||||
new HttpEntity<>(body, headers),
|
"-F", "SIG=" + sigJson,
|
||||||
String.class);
|
"https://api.developer.xiaomi.com/devupload/dev/push"
|
||||||
JsonNode root = mapper.readTree(Objects.requireNonNull(response.getBody()));
|
);
|
||||||
|
pb.redirectErrorStream(true);
|
||||||
|
Process process = pb.start();
|
||||||
|
String responseBody = new String(process.getInputStream().readAllBytes(), StandardCharsets.UTF_8).trim();
|
||||||
|
boolean completed = process.waitFor(130, java.util.concurrent.TimeUnit.MINUTES);
|
||||||
|
if (!completed) {
|
||||||
|
process.destroyForcibly();
|
||||||
|
throw new IllegalStateException("curl upload to MI timed out");
|
||||||
|
}
|
||||||
|
if (responseBody.isEmpty()) {
|
||||||
|
throw new IllegalStateException("curl upload to MI returned empty response (exit=" + process.exitValue() + ")");
|
||||||
|
}
|
||||||
|
JsonNode root = mapper.readTree(responseBody);
|
||||||
miCheckSuccess(root, "上传Apk");
|
miCheckSuccess(root, "上传Apk");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
正在加载...
在新工单中引用
屏蔽一个用户