Apache HttpComponents Async Client设置请求主体的问题

huangapple go评论77阅读模式
英文:

Apache HttpComponents Async Client Setting Request Body Issue

问题

我正在学习最新的apache hc异步客户端的示例。响应流式传输功能非常有用,正是我需要的(比如在每个数据块到达时计算延迟,这在CloseableHttpClient中似乎缺失)。

但是在设置请求体方面遇到了问题。

AsyncClientHttpExchangeStreaming为例,我可以运行此示例,但是当尝试添加一些请求体时,比如以下内容,我发现它不起作用(httpbin的响应非常清楚,datajson字段为空)。

      String bodyString = "{\"k\":\"v\"}";
      final SimpleHttpRequest request = SimpleRequestBuilder
        .post()
        .setHttpHost(target)
        .setPath("/post")
        .setBody(bodyString, ContentType.APPLICATION_JSON)
        .build();

然后我注意到client.execute(new BasicRequestProducer(request, null),并尝试将null替换为new BasicAsyncEntityProducer(bodyString, ContentType.APPLICATION_JSON);,这次httpbin告诉我它接收到了bodyString(这个解决方法是否正确以及为什么需要?)。

当我尝试像上面的解决方法一样发布多部分表单时,服务器报告错误,如'content-length missing'或'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();
    //上面的reqEntity可以在同步客户端中成功请求我的服务器
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    reqEntity.writeTo(baos);
    byte[] bytes = baos.toByteArray();
    BasicAsyncEntityProducer multiPartProducer = new BasicAsyncEntityProducer(
        bytes,
        ContentType.MULTIPART_FORM_DATA
    );

我搜索了很多,有人MultipartEntityBuilder创建的HttpEntity不能与异步客户端一起使用。我感到非常失望和沮丧。有人能否建议在apache hc中正确的方法,或者是否有其他库可以代替?

英文:

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?

答案1

得分: 0

"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)
```"

<details>
<summary>英文:</summary>

  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.
```java
//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(&quot;Content-Type&quot;, contentType)

huangapple
  • 本文由 发表于 2023年3月9日 14:12:57
  • 转载请务必保留本文链接:https://go.coder-hub.com/75680994.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定