question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Feign Request returnType Response.class with "Transfer-Encoding: chunked"

See original GitHub issue

Why the reponse type is Response.class and feign.Response#body should not close when response data with header “Transfer-Encoding: chunked” and not contain “Content-Length”? response.body().length() will return null and shouldClose variable will be set to false.

feign.AsyncResponseHandler#handleResponse

  void handleResponse(CompletableFuture<Object> resultFuture,
                      String configKey,
                      Response response,
                      Type returnType,
                      long elapsedTime) {
    // copied fairly liberally from SynchronousMethodHandler
    boolean shouldClose = true;

    try {
      if (logLevel != Level.NONE) {
        response = logger.logAndRebufferResponse(configKey, logLevel, response,
            elapsedTime);
      }
      if (Response.class == returnType) {
        if (response.body() == null) {
          resultFuture.complete(response);
        } else if (response.body().length() == null
            || response.body().length() > MAX_RESPONSE_BUFFER_SIZE) {
          shouldClose = false;
          resultFuture.complete(response);
        } else {
          // Ensure the response body is disconnected
          final byte[] bodyData = Util.toByteArray(response.body().asInputStream());
          resultFuture.complete(response.toBuilder().body(bodyData).build());
        }
       // ...
    } catch (final IOException e) {
      if (logLevel != Level.NONE) {
        logger.logIOException(configKey, logLevel, e, elapsedTime);
      }
      resultFuture.completeExceptionally(errorReading(response.request(), response, e));
    } catch (final Exception e) {
      resultFuture.completeExceptionally(e);
    } finally {
      if (shouldClose) {
        ensureClosed(response.body());
      }
    }
  }

If I don’t use try-with-resource process response feign.Response#body,apache httpclient can’t re-use the connection,which waiting for get connection forever. some tests which waiting for get connection forever:

public class ApacheHttpClientTest extends AbstractClientTest {

  @Override
  public Builder newBuilder() {
    return Feign.builder().client(new ApacheHttpClient());
  }

  @Test
  public void responseNotClose() {
    final HttpClient httpClient = HttpClientBuilder.create()
            .setMaxConnPerRoute(1)
            .setMaxConnTotal(1)
            .build();

    final NoContentInterface testInterface = Feign.builder()
            .client(new ApacheHttpClient(httpClient))
            .target(NoContentInterface.class, "http://localhost:" + server.getPort());

    server.enqueue(new MockResponse().setResponseCode(201).setChunkedBody("", -1));
    server.enqueue(new MockResponse().setResponseCode(201).setChunkedBody("", -1));

    Response res1 = testInterface.NoContent1("test1");
    assertNotNull(res1);
	
    System.out.println("waiting.....");

    Response res2 = testInterface.NoContent1("test2");
    assertNotNull(res2);
    System.out.println("end.....");
  }

  public interface NoContentInterface {
    @RequestLine("POST /no-content1")
    Response NoContent1(@QueryParam("foo") String foo);
  }
}

However, after I enable feign log output, feign.Logger#logAndRebufferResponse will rebuild response body with using feign.Util#toByteArray,feign.Response#body will consume and apache httpclient re-use this connection.

I don’t understand why it isn’t necessary to close feign.Response#body.If I enable feign log output, feign.Response#body is consumed in the end. I think it should be also rebuild response body with using feign.Util#toByteArray .Look forward to your reply.

Issue Analytics

  • State:open
  • Created 2 years ago
  • Comments:7 (4 by maintainers)

github_iconTop GitHub Comments

1reaction
kdavisk6commented, Mar 25, 2022

@hdfg159 It looks like our documentation is missing one very key piece of information. If your Feign interface returns a Feign.Response object, the caller is responsible closing the Response. We should add that documentation.

Although it is the omission of the document, I don’t know why the caller is responsible closing the Response🙄

By obtaining the Response, Feign relinquishes control to the caller, who is now responsible for handling the response, dealing with any errors, decoding the body, retrying, etc… This is the trade off for using Response objects directly.

0reactions
kdavisk6commented, Mar 25, 2022

An example of proper use: Interface:

public interface MyApi {
   @RequestLine("GET /data"
   Response getData();
}

Use of the method

public static void main(String[] args) {
   MyApi api = Feign.target(MyApi.class);

   try (Response response = api.getData()) {
      /* process the response */
   }
}

Hi Kevin, Thanks for your reply. I think the issue is specific to Feign with apache http client handling with ‘Transfer-Encoding’ header.

See the source code in 1st comment:

    } else if (response.body().length() == null
        || response.body().length() > MAX_RESPONSE_BUFFER_SIZE) {
      shouldClose = false;
      resultFuture.complete(response);
    }

If shouldClose is set to false, then it won’t execute the below:

finally { if (shouldClose) { ensureClosed(response.body()); } }

This issue doesn’t happen in Feign + okhttp client.

Thanks.

Kelvin J Li

This sounds like a bug, would you be able to create a minimal reproducible example and submit a new issue?

Read more comments on GitHub >

github_iconTop Results From Across the Web

Remove Transfer-Encoding:chunked in the POST request?
I am sending a POST request using the following code but the request is send in the form of chunked ( Transfer-Encoding: chunked...
Read more >
Chunked Entities - endpoints4s
This algebra provides vocabulary to describe endpoints whose requests or responses are streamed using the “chunked transfer-encoding” supported by HTTP1.1.
Read more >
spring-cloud/spring-cloud - Gitter
I just tried it with a 200 MB response payload. The originating server sets Content-Length: 209715200 and through Zuul it's Transfer-Encoding: chunked ....
Read more >
Bad chunk header mystery - Medium
Header: [Transfer-Encoding] > [chunked]. For easier, here is normal response's headers: Header: [Content-Type] > [application/json ...
Read more >
File Upload With Open Feign - Baeldung
So, to explain the file upload via Feign client, we'll call the exposed web service API ... Let's add @EnableFeignClients to our main...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found