I'm learning examples of latest apache hc async client. The response streaming feature is very useful and exactly what I need(such as calculating latency when each chunk arrived, which seems lack in CloseableHttpClient
).
But having trouble setting the request body.
Take the AsyncClientHttpExchangeStreaming as example, I can run this example, but when trying to add some body to request, like following, I find it not work(httpbin response is very clear, and data
or json
field is empty).
String bodyString = "{\"k\":\"v\"}";
final SimpleHttpRequest request = SimpleRequestBuilder
.post()
.setHttpHost(target)
.setPath("/post")
.setBody(bodyString, ContentType.APPLICATION_JSON)
.build();
Then I noticed client.execute(new BasicRequestProducer(request, null),
and tried to replace null
with
new BasicAsyncEntityProducer(bodyString, ContentType.APPLICATION_JSON);
, this time httpbin tells me it received the bodyString(is this walkaround correct and why need?).
When I tried posting multi part form, like above walkaround, the server reports errors such as 'content-length missing' or 'malformed request':
final StringBody inputBody = new StringBody(inputJson, ContentType.APPLICATION_JSON);
final StringBody parametersBody = new StringBody(parametersJson, ContentType.APPLICATION_JSON);
final HttpEntity reqEntity = MultipartEntityBuilder.create()
.addPart("Input", inputBody)
.addPart("Parameters", parametersBody)
.build();
//above reqEntity can successful request my server in sync client
ByteArrayOutputStream baos = new ByteArrayOutputStream();
reqEntity.writeTo(baos);
byte[] bytes = baos.toByteArray();
BasicAsyncEntityProducer multiPartProducer = new BasicAsyncEntityProducer(
bytes,
ContentType.MULTIPART_FORM_DATA
);
I searched a lot and someone says the HttpEntity
created by MultipartEntityBuilder
cannot be used along with async client. I'm very disappointed and frustrated. Could anyone suggest the correct way in apache hc, or rather other libraries instead?
Found solution and answer myself, hope helpful for some newcomers like me. Still welcome more elgant solution.
Cause of the issue
HttpEntity
created by MultipartEntityBuilder
is wrapped into BasicAsyncEntityProducer
as bytes, library sends the bytes as they are, and http post header missing boundary information.
Solution
Get the Content-Type
header including the boundery info then update it into request headers.
//get the `Content-Type` header including the boundery info
//value is like:
//Content-Type: multipart/form-data; charset=ISO-8859-1; boundary=fLC0K1nKdSI-Q9vzFpU2WleMTXyWbOBp6
String contentType = reqEntity.getContentType();
final SimpleHttpRequest request = SimpleRequestBuilder
//...omit other methods
.setHeader("Content-Type", contentType)