Apache HTTP/2 Client 5.0 POST-запрос отсутствует полезная нагрузка/контент

У меня есть небольшой пример сервлета, развернутого на Tomcat, который будет возвращать любые полученные параметры. Tomcat настроен на поддержку HTTP/1.1 и HTTP/2. Я могу использовать curl для выполнения запросов GET к сервлету, демонстрируя, что он работает как по HTTP/1.1, так и по HTTP/2.

Используя клиент Apache HTTP 5.0, у меня есть модульный тест для обращения к сервлету и POST запрос с некоторыми параметрами (содержимое запроса), который работает нормально - сервер получает параметры и возвращает их клиенту, где я могу их прочитать. В этом тесте я призываю клиента использовать HTTP/1.1 или HTTP/2, используя вызов CloseableHttpAsyncClient.setVersionPolicy(). Однако, если я перейду на использование HTTP/2, клиент не отправит содержимое запроса на сервер.

Ниже приведен пример кода для успешного вызова HTTP/1.1 — вы можете видеть, что у меня есть setVersionPolicy(HttpVersionPolicy.FORCE_HTTP_1). Если я изменю это на FORCE_HTTP_2, тогда вызов будет выполнен через HTTP/2.0, но содержимое запроса не будет отправлено.

Может ли кто-нибудь предложить, что я делаю неправильно или что еще мне нужно сделать? Я не нашел много документации по использованию новых клиентских библиотек Apache 5.0, а в примерах не показана отправка и POST-контент (по крайней мере, те, что я могу найти).

    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);
    }

comment
Опубликуйте протокол сеанса здесь или по адресу [email protected].   -  person ok2c    schedule 07.03.2021


Ответы (2)


HTTP/1 может быть реализован через HTTP и HTTPS, но для HTTP/2 он реализован только в HTTPS.

Из того, что я вижу, вы звоните только по URL-адресу http, возможно, это причина, по которой сервлет не может получить содержимое полезной нагрузки.

См. более подробности

person Wang Du    schedule 02.03.2021
comment
Спасибо, это побудило меня провести еще несколько тестов с CURL. Я думал, что мой сервер tomcat работает с HTTP/2 как на HTTP, так и на HTTPS. Однако использование HTTP/2 не так однозначно. Я могу использовать CURL для выполнения запросов HTTP/2 POST для соединений без SSL, но только если нет полезной нагрузки. Я также могу выполнять запросы HTTP/2 GET с параметрами URL или без них как для HTTP, так и для HTTPS. Таким образом, кажется, что добавление содержимого тела к запросу HTTP/2 без SSL приведет к понижению до HTTP/1. В моих тестах я могу успешно добавить содержимое тела в запрос HTTP/2, поэтому, как вы указываете, мне нужно отправлять запросы на сервер HTTPS. - person JohnXF; 02.03.2021

Похоже, что у них есть совершенно другой билдер для Http/2, глядя на их исходный код:

/**
 * Creates builder object for construction of custom HTTP/2
 * {@link CloseableHttpAsyncClient} instances optimized for HTTP/2 protocol
 * and message multiplexing
 */
public static H2AsyncClientBuilder customHttp2() {
    return H2AsyncClientBuilder.create();
}

/**
 * Creates HTTP/2 {@link CloseableHttpAsyncClient} instance with default configuration and
 * system properties optimized for HTTP/2 protocol and message multiplexing.
 */
public static CloseableHttpAsyncClient createHttp2System() {
    return H2AsyncClientBuilder.create().useSystemProperties().build();
}

Поэтому я предлагаю вам попробовать настоящий customHttp2() вместо custom().

https://github.com/apache/httpcomponents-client/blob/master/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/HttpAsyncClients.java< /а>

person Susan Mustafa    schedule 02.03.2021
comment
Спасибо, Сьюзан, но радости нет. Использование customHttp2() даст мне ClientBuilder, из которого я получу еще один CloseableHttpAsyncClient, но продолжая, как и раньше, я все равно получаю тот же результат. - person JohnXF; 02.03.2021
comment
@Susan Mustafa Этот конструктор предназначен для тех пользователей, которые хотели бы использовать только протокол HTTP/2 и в полной мере воспользоваться преимуществами мультиплексирования обмена сообщениями. - person ok2c; 07.03.2021