Search code examples
javahttp2apache-httpcomponentsapache-httpasyncclientapache-httpclient-5.x

Apache HTTP/2 Client 5.0 POST request missing payload/content


I have a small sample servlet deployed to a Tomcat that will echo back any received parameters. The Tomcat is configured to support HTTP/1.1 and HTTP/2. I can use curl to make GET requests to the servlet demonstrating it works over both HTTP/1.1 and HTTP/2.

Using the Apache HTTP 5.0 client I have a unit test to hit the servlet and POST a request with some parameters (request content) that works fine - the server receives the parameters and returns them back to the client where I can read them. In this test I call the client to use HTTP/1.1 or HTTP/2 using the CloseableHttpAsyncClient.setVersionPolicy() call. However, if I change to use HTTP/2 then the client does not send the request content to the server.

Below is the example code for a successful HTTP/1.1 call - you can see I have setVersionPolicy(HttpVersionPolicy.FORCE_HTTP_1). If I change that to FORCE_HTTP_2 then the call is made over HTTP/2.0 but the request content is not sent.

Can anyone suggest what I am doing wrong or what extra I need to do? I have not found a lot of documentation on the use of the new Apache 5.0 client libraries, and the examples do not show sending and POST content (or at least those I can find).

    public void testWithHTTP1() throws Exception {

        final String content = "Code=99&Message=Hello";
        final String contentType = "application/text";

        final CloseableHttpAsyncClient client = HttpAsyncClients.custom()
                .setVersionPolicy(HttpVersionPolicy.FORCE_HTTP_1)
                .build();

        client.start();

        final HttpHost target = new HttpHost("http","localhost",8002);
        final String requestUri = "/VSFTestMT_Test/Test/Test_EchoHttpGet";

        final HttpClientContext clientContext = HttpClientContext.create();

        final SimpleHttpRequest httppost = SimpleHttpRequests.post(target, requestUri);     
        httppost.setBody(content, ContentType.create("application.x_www_form_urlencoded"));
        
        final Future<SimpleHttpResponse> future = client.execute(
                httppost,
                clientContext,
                new FutureCallback<SimpleHttpResponse>() {

                    @Override
                    public void completed(final SimpleHttpResponse response) {
                        System.out.println(requestUri + "->" + response.getCode());
                        System.out.println(response.getBody());
                    }

                    @Override
                    public void failed(final Exception ex) {
                        System.out.println(requestUri + "->" + ex);
                    }

                    @Override
                    public void cancelled() {
                        System.out.println(requestUri + " cancelled");
                    }

                });


        System.out.println("Shutting down");
        client.close(CloseMode.GRACEFUL);
    }

Solution

  • HTTP/1 can be implemented via HTTP and HTTPS, but for HTTP/2 its implemented in HTTPS only.

    From what I can see you are calling http url only, might be that is the reason why servlet is not able to fetch payload content

    Please see this more detail