Построение составного запроса из InputStream с помощью HTTP-клиента Apache Async - PullRequest
0 голосов
/ 04 февраля 2019

Я пытаюсь отправить многокомпонентный запрос через асинхронный http-клиент apache, но получаю ошибку org.apache.http.ContentTooLongException: Content length is unknown.

Я понимаю, почему длина содержимого требуется в асинхронной модели, но хочу понять, является ли этоэто сделано по замыслу или это ошибка?

Я ожидаю, что он загрузит поток в буфер памяти и использует его (это то, что делает AsyncHttpClient).

Мой тестовый сценарий использования:

public class InputStreamAsMultipartPayloadTest {

    @Rule
    public WireMockClassRule instanceRule = new WireMockClassRule(9090);


    @Test
    public void inputStreamPartTest() throws Exception {

        String partBody = "hello";
        instanceRule.stubFor(any(urlPathEqualTo("/hello"))
                .withMultipartRequestBody(
                        aMultipart()
                                .withName("part-name")
                                .withHeader("Content-Type", equalTo("application/octet-stream"))
                                .withHeader("Content-Transfer-Encoding", equalTo("binary"))
                                .withBody(equalTo(partBody)))
                .willReturn(aResponse()));

        byte[] body = partBody.getBytes(UTF_8);

        try (CloseableHttpAsyncClient httpAsyncClient = HttpAsyncClients.createDefault()) {
            httpAsyncClient.start();
            HttpPost postRequest = new HttpPost(URI.create("/hello"));

            MultipartEntityBuilder multipartBuilder = MultipartEntityBuilder.create();
            multipartBuilder.addBinaryBody("part-name", new ByteArrayInputStream(body));
            postRequest.setEntity(multipartBuilder.build());

            Future<HttpResponse> fHttpResponse = httpAsyncClient.execute(HttpHost.create("http://localhost:9090"), postRequest, null);

            assertThat(fHttpResponse.get(3, TimeUnit.SECONDS).getStatusLine().getStatusCode()).isEqualTo(HttpURLConnection.HTTP_OK);
        }
    }

}

Трассировка стека исключений:

Caused by: org.apache.http.ContentTooLongException: Content length is unknown
    at org.apache.http.entity.mime.MultipartFormEntity.getContent(MultipartFormEntity.java:101)
    at org.apache.http.nio.entity.EntityAsyncContentProducer.produceContent(EntityAsyncContentProducer.java:65)
    at org.apache.http.nio.protocol.BasicAsyncRequestProducer.produceContent(BasicAsyncRequestProducer.java:125)
    at org.apache.http.impl.nio.client.MainClientExec.produceContent(MainClientExec.java:262)
    at org.apache.http.impl.nio.client.DefaultClientExchangeHandlerImpl.produceContent(DefaultClientExchangeHandlerImpl.java:140)
    at org.apache.http.nio.protocol.HttpAsyncRequestExecutor.outputReady(HttpAsyncRequestExecutor.java:241)
    at org.apache.http.impl.nio.DefaultNHttpClientConnection.produceOutput(DefaultNHttpClientConnection.java:290)
    at org.apache.http.impl.nio.client.InternalIODispatch.onOutputReady(InternalIODispatch.java:86)
    at org.apache.http.impl.nio.client.InternalIODispatch.onOutputReady(InternalIODispatch.java:39)
    at org.apache.http.impl.nio.reactor.AbstractIODispatch.outputReady(AbstractIODispatch.java:145)
    at org.apache.http.impl.nio.reactor.BaseIOReactor.writable(BaseIOReactor.java:188)
    at org.apache.http.impl.nio.reactor.AbstractIOReactor.processEvent(AbstractIOReactor.java:341)
    at org.apache.http.impl.nio.reactor.AbstractIOReactor.processEvents(AbstractIOReactor.java:315)
    at org.apache.http.impl.nio.reactor.AbstractIOReactor.execute(AbstractIOReactor.java:276)
    at org.apache.http.impl.nio.reactor.BaseIOReactor.execute(BaseIOReactor.java:104)
    at org.apache.http.impl.nio.reactor.AbstractMultiworkerIOReactor$Worker.run(AbstractMultiworkerIOReactor.java:588)

Полный исходный код можно найти по адресу: https://github.com/maximkir/apache-async-http

В общем, я являюсь автором SHCF4J (простой HTTP-клиент для Java), который стремится предоставить унифицированный фасад для общих случаев использования HTTP-клиента.Я могу исправить это на уровне фасада, но предпочитаю, чтобы его логика была минимальной.

...