将文件从预签名 URL (GET) 传输到另一个 URL (PUT) 时出现以下错误。当我并行调用我的 API 超过 3 次时,就会发生这种情况。
例如,如果我调用它10次。 3 传输将在 1 分钟内完成,然后在我的 POD 监控中 CPU 使用率将降至 0,15 分钟后我将收到错误。
java.io.IOException: Error writing request body to server
at java.base/sun.net.www.protocol.http.HttpURLConnection$StreamingOutputStream.checkError(HttpURLConnection.java:3807)
at java.base/sun.net.www.protocol.http.HttpURLConnection$StreamingOutputStream.write(HttpURLConnection.java:3789)
...
at java.base/java.lang.Thread.run(Thread.java:833)
Suppressed: java.io.IOException: insufficient data written
at java.base/sun.net.www.protocol.http.HttpURLConnection$StreamingOutputStream.close(HttpURLConnection.java:3834)
at .....
... 3 more
我的方法:
public ResponseEntity<String> transferData(Config config) throws IOException {
var inputUrl = config.getInputdUrl();
var outputUrl = config.getOutputdUrl();
var uploadConnection = uploader.getUploadConnection(outputUrl);
try (var inputStream = downloader.getDownloadConnection(inputUrl).getInputStream();
var outputStream = uploadConnection.getOutputStream()) {
IOUtils.copyLarge(inputStream, outputStream);
outputStream.flush();
var resp = uploadConnection.getResponseCode();
return ResponseEntity
.status(HttpStatus.OK)
.body("Transfer done with response:" + resp);
} catch (IOException ioe) {
return ResponseEntity
.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body("An error occurred while transferring data : " + ioe);
}
}
我通过执行以下操作在 springboot 控制器中调用此方法:
new Thread(() -> transferDataToScality(...)).start();
return ResponseEntity.ok("Downloading data in asynchronous mode successfully started");
我怎样才能避免这个问题?
只要你还没有完成对uploadConnection的写入,就没有任何响应。 在检查响应代码之前关闭流:
try (var inputStream = downloader.getDownloadConnection(inputUrl).getInputStream();
var outputStream = uploadConnection.getOutputStream()) {
IOUtils.copyLarge(inputStream, outputStream);
} catch (IOException ioe) {
return ResponseEntity
.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body("An error occurred while transferring data : " + ioe);
}
var resp = uploadConnection.getResponseCode();
return ResponseEntity
.status(HttpStatus.OK)
.body("Transfer done with response:" + resp);
注意我删除了对outputStream.flush()的调用。 不需要它,因为关闭 InputStream 或 OutputStream 总是会刷新它。
你也不需要像 IOUtils 这样的第三方类。 只需使用 transferTo:
try (var inputStream = downloader.getDownloadConnection(inputUrl).getInputStream();
var outputStream = uploadConnection.getOutputStream()) {
inputStream.transferTo(outputStream);
} catch (IOException ioe) {