Вызов Java HTTP API - потоковая передача и потоковая передача данных
У меня есть служба передачи файлов, написанная на Java и Spring boot, где она передает файлы из источника в пункт назначения без какого-либо локального хранилища.
Он получает дескрипторы InputStream из источника и OutputStream для назначения и эффективно выполняет следующие действия для потоковой передачи файла.
IOUtils.copy(inputStream, outputStream);
Destination InputStream -> IOUtils.copy -> Destination OutputStream
Теперь у меня есть еще одно требование: мне нужно вызвать API шифрования, который принимает поток приложения / окт-и т. Д. И возвращает то же самое. API шифрует данные, когда клиент передает данные, и в то же время возвращает данные в виде потока. Я протестировал API с помощью curl, используя следующую команду:
curl -v -X POST -H "Content-Type:application/octet-stream" -H "Accept:application/octet-stream" --data-binary @test-file -o test-file.enc http://127.0.0.1:1234/encrypt/test-file
Теперь мне нужно интегрировать этот API шифрования с моей исходной службой передачи файлов, где я могу получить дескриптор исходного InputStream, передать его в запрос API, получить InputStream из ответа API и подключить его в свой исходный вызов IOUtils.copy для передачи данные к месту назначения:
Destination InputStream -> Encryption API -> Encrypted InputStream -> IOUtils.copy -> Destination OutputStream
Для реализации вызова API шифрования сначала я пытаюсь создать клиента, передать FileInputStream и извлечь ответ в FileOutputStream. Я пробовал как Apache HTTPClient, так и Spring RestTemplate. В обоих случаях с небольшими файлами он работает, как ожидалось, однако с большими файлами API шифрования получает только часть данных, и кажется, что он застрял там. Исходный вызывающий абонент (служба передачи файлов) также не получает ответа и зависает. Поведение идентично в обеих реализациях.
Реализация с HTTPClient:
InputStream unencryptedInputStream = new FileInputStream("test-file");
HttpClient httpclient = HttpClients.createDefault();
URIBuilder builder = new URIBuilder("http://127.0.0.1:1234/encrypt/test-file");
HttpPost request = new HttpPost(builder.build());
request.setHeader("Content-Type", "application/octet-stream");
InputStreamEntity inputStreamEntity = new InputStreamEntity(unencryptedInputStream, 1064041488);
inputStreamEntity.setContentType("application/octet-stream");
inputStreamEntity.setChunked(true);
request.setEntity(inputStreamEntity );
HttpResponse response = httpclient.execute(request);
HttpEntity entity = response.getEntity();
InputStream encryptedInputStream = entity.getContent();
OutputStream os = new FileOutputStream("test-file.enc");
IOUtils.copy(encryptedInputStream, os);
Реализация с помощью Spring RestTemplate:
RestTemplate restTemplate = new RestTemplate();
InputStream unencryptedInputStream = new FileInputStream("test-file");
OutputStream encryptedOutputStream = new FileOutputStream("test-file.enc");
SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
requestFactory.setBufferRequestBody(false);
restTemplate.setRequestFactory(requestFactory);
RequestCallback requestCallback = new RequestCallback() {
@Override
public void doWithRequest(ClientHttpRequest clientHttpRequest) throws IOException {
clientHttpRequest.getHeaders().add("Content-type", "application/octet-stream");
clientHttpRequest.getHeaders().add("Accept", "application/octet-stream");
IOUtils.copy(unencryptedInputStream, clientHttpRequest.getBody());
}
};
ResponseExtractor<InputStream> responseExtractor = new ResponseExtractor<InputStream>() {
@Override
public InputStream extractData(ClientHttpResponse clientHttpResponse) throws IOException {
IOUtils.copy(clientHttpResponse.getBody(), encryptedOutputStream);
return clientHttpResponse.getBody();
}
};
restTemplate.execute("http://127.0.0.1:1234/encrypt/test-file", HttpMethod.POST, requestCallback, responseExtractor);
Оба случая работают с небольшими файлами, но зависают с большими файлами. Я попытался обернуть запрос IOUtils.copy в потоке "Runnable", но проблема все равно осталась.