httpclient utilizado por la biblioteca de herramientas de código abierto de Java

prefacio

HttpClient se estableció en 2001 como un subproyecto del proyecto Apache Jakarta Commons . Dejó Commons en 2004y se promovió para convertirse en un proyecto independiente de Jakarta. En 2005, Jakarta creó el proyecto HttpComponents con el objetivo de desarrollarel sucesor de HttpClient 3.x. En 2007,proyecto Commons , que es el lugar de nacimiento del proyecto HttpClient , salió de Yakarta y se convirtió en un nuevo proyecto de primer nivel. Poco después, HttpComponents también abandonó Yakarta y se convirtió en un proyecto independiente de alto nivel responsable del mantenimiento de HttpClient .

  • HttpClient proporciona un kit de herramientas de programación de clientes eficiente, actualizado y rico en funciones que admite el protocolo HTTP y admite la última versión del protocolo HTTP .

  • El proyecto HttpComponents incluye tres módulos : HttpClient , HttpCore y AsyncClient , que brindan un mejor rendimiento y una mayor flexibilidad .

  • HttpClient depende de HttpCore , la última versión de HttpClient es 5.2

  • HttpClient está separado por la versión 3.1 y existen muchas diferencias de uso entre las versiones principales.

  • Dirección del documento más reciente: https://hc.apache.org/httpcomponents-client-5.2.x/index.html

  • Dirección del documento anterior: https://hc.apache.org/httpclient-legacy/userguide.html

  • dirección de github: https://github.com/apache/httpcomponents-client

  • dependencias pom

    <!-- 最新版本5 -->
    <dependency>
        <groupId>org.apache.httpcomponents.client5</groupId>
        <artifactId>httpclient5</artifactId>
        <version>5.2.1</version>
    </dependency>
    
    <!-- 版本4 -->
    <dependency>
        <groupId>org.apache.httpcomponents</groupId>
        <artifactId>httpclient</artifactId>
        <version>4.5.13</version>
    </dependency>
    
    <!-- 旧版本3,07年后没更新 -->
    <dependency>
        <groupId>commons-httpclient</groupId>
        <artifactId>commons-httpclient</artifactId>
        <version>3.1</version>
    </dependency>
    

1. Fácil de usar

1.1 obtener solicitud

String url = "http://httpbin.org/get";
try (final CloseableHttpClient httpclient = HttpClients.createDefault()) {
    
    
    final HttpGet httpget = new HttpGet(url);

    // Create a custom response handler
    final HttpClientResponseHandler<String> responseHandler = response -> {
    
    
        final int status = response.getCode();
        if (status >= HttpStatus.SC_SUCCESS && status < HttpStatus.SC_REDIRECTION) {
    
    
            final HttpEntity entity = response.getEntity();
            try {
    
    
                return entity != null ? EntityUtils.toString(entity) : null;
            } catch (final ParseException ex) {
    
    
                throw new ClientProtocolException(ex);
            }
        } else {
    
    
            throw new ClientProtocolException("Unexpected response status: " + status);
        }
    };
    final String responseBody = httpclient.execute(httpget, responseHandler);
    System.out.println(responseBody);
}

1.2 publicar solicitud de formulario simple

String url = "http://httpbin.org/post";
String username = "root";
String loginPw = "";
try (final CloseableHttpClient httpclient = HttpClients.createDefault()) {
    
    
    final HttpPost httppost = new HttpPost(url);
    final List<NameValuePair> params = new ArrayList<>();
    params.add(new BasicNameValuePair("username", username));
    params.add(new BasicNameValuePair("password", loginPw));
    httppost.setEntity(new UrlEncodedFormEntity(params));

    // Create a custom response handler
    final HttpClientResponseHandler<String> responseHandler = response -> {
    
    
        final int status = response.getCode();
        if (status >= HttpStatus.SC_SUCCESS && status < HttpStatus.SC_REDIRECTION) {
    
    
            final HttpEntity entity = response.getEntity();
            try {
    
    
                return entity != null ? EntityUtils.toString(entity) : null;
            } catch (final ParseException ex) {
    
    
                throw new ClientProtocolException(ex);
            }
        } else {
    
    
            throw new ClientProtocolException("Unexpected response status: " + status);
        }
    };
    final String responseBody = httpclient.execute(httppost, responseHandler);
    System.out.println(responseBody);
}

1.3 Archivo de carga de formulario

final HttpPost httppost = new HttpPost(url);
            
final MultipartEntityBuilder builder = MultipartEntityBuilder.create();
builder.addTextBody("username", username);
builder.addTextBody("password", password);
builder.addBinaryBody("file", new File("src/test/resources/test.txt"), ContentType.APPLICATION_OCTET_STREAM, "test.txt");

final HttpEntity multipart = builder.build();

httppost.setEntity(multipart);

1.4 cargar datos json

final HttpPost httppost = new HttpPost(url);

httppost.setHeader("Accept", "application/json");
httppost.setHeader("Content-type", "application/json");

final String json = "{\"id\":1,\"name\":\"John\"}";
final StringEntity stringEntity = new StringEntity(json);
httppost.setEntity(stringEntity);

2. Uso avanzado

2.1 Tiempos de espera y reintentos

El control de tiempo de espera puede ser controlado por la clase RequestConfig

String url = "http://httpbin.org/get";

RequestConfig requestConfig = RequestConfig.custom()
    .setConnectionRequestTimeout(Timeout.ofSeconds(100L))//连接请求超时, 0为无限。默认值:3分钟。
    .setResponseTimeout(Timeout.ofSeconds(600L)) // 响应超时时间,0为无限。带有消息复用的HTTP传输可能不支持响应超时
    .build();

try (final CloseableHttpClient httpclient = HttpClients.createDefault()) {
    
    
    final HttpGet httpGet = new HttpGet(url);
    httpGet.setConfig(requestConfig);
    final HttpClientResponseHandler<String> responseHandler = response -> {
    
    
        final int status = response.getCode();

        if (status >= HttpStatus.SC_SUCCESS && status < HttpStatus.SC_REDIRECTION) {
    
    
            final HttpEntity entity = response.getEntity();
            try {
    
    
                return entity != null ? EntityUtils.toString(entity) : null;
            } catch (final ParseException ex) {
    
    
                throw new ClientProtocolException(ex);
            }
        } else {
    
    
            throw new ClientProtocolException("Unexpected response status: " + status);
        }
    };
    httpclient.execute(httpGet, responseHandler);
}

Reintentar, la política de reintento predeterminada es el número máximo de veces 1 y el intervalo de reintento es de 1 segundo.

String url = "http://httpbin.org/get";

try (final CloseableHttpClient httpclient = HttpClients.custom()
     .setRetryStrategy(new DefaultHttpRequestRetryStrategy(3, TimeValue.ofSeconds(20L)))
     .build()) {
    
    
    final HttpGet httpGet = new HttpGet(url);

    final HttpClientResponseHandler<String> responseHandler = response -> {
    
    
        final int status = response.getCode();

        if (status >= HttpStatus.SC_SUCCESS && status < HttpStatus.SC_REDIRECTION) {
    
    
            final HttpEntity entity = response.getEntity();
            try {
    
    
                return entity != null ? EntityUtils.toString(entity) : null;
            } catch (final ParseException ex) {
    
    
                throw new ClientProtocolException(ex);
            }
        } else {
    
    
            throw new ClientProtocolException("Unexpected response status: " + status);
        }
    };
    httpclient.execute(httpGet, responseHandler);
}

2.2 Galletas

HttpClients.createDefault tiene un administrador de cookies predeterminado incorporado que se puede usar para transportar cookies para el acceso

String url = "http://httpbin.org/cookies/set/foo/bar";
String url2 = "http://httpbin.org/cookies";

try (final CloseableHttpClient httpclient = HttpClients.createDefault()) {
    
    
    final HttpGet httpGet = new HttpGet(url);

    final HttpClientResponseHandler<String> responseHandler = response -> {
    
    
        final int status = response.getCode();

        if (status >= HttpStatus.SC_SUCCESS && status < HttpStatus.SC_REDIRECTION) {
    
    
            final HttpEntity entity = response.getEntity();
            try {
    
    
                return entity != null ? EntityUtils.toString(entity) : null;
            } catch (final ParseException ex) {
    
    
                throw new ClientProtocolException(ex);
            }
        } else {
    
    
            throw new ClientProtocolException("Unexpected response status: " + status);
        }
    };
    final HttpGet httpGet2 = new HttpGet(url2);

    String responseBody2 = httpclient.execute(httpGet2, responseHandler);
    System.out.println(responseBody2);

    final String responseBody = httpclient.execute(httpGet, responseHandler);
    System.out.println(responseBody);

    responseBody2 = httpclient.execute(httpGet2, responseHandler);
    System.out.println(responseBody2);
}

También puede acceder a la información de las cookies vinculada al contexto local.

String url = "http://httpbin.org/cookies/set/foo/bar";

try (final CloseableHttpClient httpclient = HttpClients.createDefault()) {
    
    
    // 创建一个本地的 Cookie 存储
    final CookieStore cookieStore = new BasicCookieStore();

    final HttpClientContext localContext = HttpClientContext.create();
    // 绑定 cookieStore 到 localContext
    localContext.setCookieStore(cookieStore);

    final HttpGet httpget = new HttpGet(url);

    final HttpClientResponseHandler<String> responseHandler = response -> {
    
    
        final int status = response.getCode();

        if (status >= HttpStatus.SC_SUCCESS && status < HttpStatus.SC_REDIRECTION) {
    
    
            final HttpEntity entity = response.getEntity();
            try {
    
    
                final List<Cookie> cookies = cookieStore.getCookies();
                for (Cookie cookie : cookies) {
    
    
                    System.out.println("Local cookie: " + cookie);
                }
                return entity != null ? EntityUtils.toString(entity) : null;
            } catch (final ParseException ex) {
    
    
                throw new ClientProtocolException(ex);
            }
        } else {
    
    
            throw new ClientProtocolException("Unexpected response status: " + status);
        }
    };

    String response = httpclient.execute(httpget, localContext, responseHandler);
    System.out.println(response);
}

2.3 Interceptores

Httpclient admite cierto procesamiento de solicitudes a través de interceptores Hay varias formas de agregar interceptores

  • addRequestInterceptorFirst
  • addRequestInterceptorLast
  • addResponseInterceptorFirst
  • addResponseInterceptorLast
  • addExecInterceptorPrimero
  • addExecInterceptorLast
  • addExecInterceptorBefore
  • agregarExecInterceptorDespués

Los interceptores agregados se pueden dividir en 3 tipos: solicitud, respuesta y ejecución, correspondientes a solicitud, respuesta y ejecución. El nombre de la ejecución de Exec está en la enumeración ChainElement. En el código fuente de la clase HttpClientBuilder, se puede encontrar que excepto CACHING se puede usar a través de la configuración, y el orden en la enumeración es también el orden de ejecución de Exec, donde la ejecución MAIN_TRANSPORT incluye la ejecución del interceptor de solicitud y respuesta

ChainElement define un conjunto de elementos que se pueden usar para crear canalizaciones de procesamiento de solicitudes HTTP, y cada elemento puede implementar funciones específicas, como agregar encabezados HTTP personalizados, agregar información de autenticación, etc.

public enum ChainElement {
    
    
    REDIRECT, COMPRESS, BACK_OFF, RETRY, CACHING, PROTOCOL, CONNECT, MAIN_TRANSPORT
}

El siguiente es un código modificado para el ejemplo del interceptor oficial

AtomicLong count = new AtomicLong();

try (final CloseableHttpClient httpclient = HttpClients.custom()
     .addExecInterceptorAfter(ChainElement.PROTOCOL.name(), "custom", (request, scope, chain) -> {
    
    
         request.setHeader("request-id", Long.toString(count.incrementAndGet()));
         return chain.proceed(request, scope);
     })
     .addExecInterceptorAfter("custom", "quit3rd", ((request, scope, chain) -> {
    
    
         final Header idHeader = request.getFirstHeader("request-id");
         if (idHeader != null && "3".equalsIgnoreCase(idHeader.getValue())) {
    
    
             final ClassicHttpResponse response = new BasicClassicHttpResponse(HttpStatus.SC_NOT_FOUND, "Oppsie");
             response.setEntity(new StringEntity("bad luck", ContentType.TEXT_PLAIN));
             return response;
         } else {
    
    
             return chain.proceed(request, scope);
         }
     }))

     .addExecInterceptorBefore(ChainElement.CONNECT.name(), "AAA", (request, scope, chain) -> {
    
    
         System.out.println("AAA");
         return chain.proceed(request, scope);
     })
     .addExecInterceptorBefore("AAA", "BBB", (request, scope, chain) -> {
    
    
         System.out.println("BBB");
         return chain.proceed(request, scope);
     })
     .addExecInterceptorAfter("AAA", "CCC", (request, scope, chain) -> {
    
    
         System.out.println("CCC");
         return chain.proceed(request, scope);
     })

     .addRequestInterceptorFirst((request, entity, context) -> {
    
    
         System.out.println("第一个request first现在获取:" + context.getAttribute("foo"));
     })
     .addRequestInterceptorFirst((request, entity, context) -> {
    
    
         System.out.println("第二个request first, 现在设置name");
         context.setAttribute("foo", "bar");
     })
     .addRequestInterceptorLast((request, entity, context) -> {
    
    
         System.out.println("第一个request last现在获取:" + context.getAttribute("foo"));
     })

     .build()) {
    
    


    for (int i = 0; i < 5; i++) {
    
    
        final HttpGet httpget = new HttpGet("http://httpbin.org/get");

        System.out.println("Executing request " + httpget.getMethod() + " " + httpget.getUri());

        httpclient.execute(httpget, response -> {
    
    
            System.out.println("----------------------------------------");
            System.out.println(httpget + "->" + new StatusLine(response));
            EntityUtils.consume(response.getEntity());
            return null;
        });
    }
}

La siguiente animación muestra la secuencia de la cadena de ejecución execChain durante la depuración

interceptor incorporado

Los siguientes son los interceptores de solicitud y respuesta en el proceso de depuración. A partir del nombre, podemos ver que excepto que la clase principal es un interceptor personalizado, el resto son autónomos y el procesamiento de cookies también se implementa a través del interceptor.

interceptor de respuesta de solicitud

2.4 API fluida

HttpClienet versión 4.5 y superior admite API fluida, la ventaja es que el código es más conciso y seguro para subprocesos.

<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>fluent-hc</artifactId>
    <version>4.5.13</version>
</dependency>
String urlGet = "http://httpbin.org/get";
String urlPost = "http://httpbin.org/post";

String response = Request.Get(urlGet)
    .addHeader("Authorization", "Bear:dw")
    .execute()
    .handleResponse(httpResponse -> {
    
    
        int code = httpResponse.getStatusLine().getStatusCode();
        if (code == HttpStatus.SC_SUCCESS) {
    
    
            return org.apache.http.util.EntityUtils.toString(httpResponse.getEntity());
        }
        return null;
    });

System.out.println(response);

String result = Request.Post(urlPost)
    .bodyForm(Form.form().add("foo", "bar").build())
    .execute()
    .returnContent()
    .asString();

System.out.println(result);

3. Uso de la antigua versión 3.1

3.1 Obtener solicitud

String url = "http://httpbin.com";
HttpClient client = new HttpClient();
GetMethod method = new GetMethod(url);
method.getParams().setParameter(HttpMethodParams.RETRY_HANDLER,
                                new DefaultHttpMethodRetryHandler(3, false));
try {
    
    
    // Execute the method.
    int statusCode = client.executeMethod(method);

    if (statusCode != HttpStatus.SC_OK) {
    
    
        System.err.println("Method failed: " + method.getStatusLine());
    }

    // Read the response body.
    byte[] responseBody = method.getResponseBody();

    // Deal with the response.
    // Use caution: ensure correct character encoding and is not binary data
    System.out.println(new String(responseBody));

} catch (HttpException e) {
    
    
    System.err.println("Fatal protocol violation: " + e.getMessage());
    e.printStackTrace();
} catch (IOException e) {
    
    
    System.err.println("Fatal transport error: " + e.getMessage());
    e.printStackTrace();
} finally {
    
    
    // Release the connection.
    method.releaseConnection();
}

3.2 Publicar solicitud

String url = "http://httpbin.org/post";
HttpClient client = new HttpClient();
PostMethod method = new PostMethod(url);
NameValuePair[] data = {
    
    
    new NameValuePair("user", "joe"),
    new NameValuePair("password", "bloggs")
};
method.setRequestBody(data);

try {
    
    
    int statusCode = client.executeMethod(method);
    if (statusCode != HttpStatus.SC_OK) {
    
    
        System.err.println("Method failed: " + method.getStatusLine());
    }
    byte[] responseBody = method.getResponseBody();
    System.out.println(new String(responseBody));
} catch (HttpException e) {
    
    
    System.err.println("Fatal protocol violation: " + e.getMessage());
    e.printStackTrace();
} catch (IOException e) {
    
    
    System.err.println("Fatal transport error: " + e.getMessage());
    e.printStackTrace();
} finally {
    
    
    method.releaseConnection();
}

En cuarto lugar, el uso de la versión asíncrona

4.1 Solicitud básica

final IOReactorConfig ioReactorConfig = IOReactorConfig.custom()
                .setSoTimeout(Timeout.ofSeconds(5))
                .build();

final CloseableHttpAsyncClient client = HttpAsyncClients.custom()
    .setIOReactorConfig(ioReactorConfig)
    .build();

client.start();

final HttpHost target = new HttpHost("httpbin.org");
final String[] requestUris = new String[] {
    
    "/", "/ip", "/user-agent", "/headers"};

for (final String requestUri: requestUris) {
    
    
    final SimpleHttpRequest request = SimpleRequestBuilder.get()
        .setHttpHost(target)
        .setPath(requestUri)
        .build();

    System.out.println("请求url:" + requestUri);
    final Future<SimpleHttpResponse> future = client.execute(
        SimpleRequestProducer.create(request),
        SimpleResponseConsumer.create(),
        new FutureCallback<SimpleHttpResponse>() {
    
    

            @Override
            public void completed(final SimpleHttpResponse response) {
    
    
                System.out.println(requestUri + " 返回状态码:" + response.getCode() + ",返回内容:" + response.getBodyText());
            }

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

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

        });
    future.get();
}

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

4.2 Solicitud de ejecución de canalización

final MinimalHttpAsyncClient client = HttpAsyncClients.createMinimal(
    H2Config.DEFAULT,
    Http1Config.DEFAULT,
    IOReactorConfig.DEFAULT,
    PoolingAsyncClientConnectionManagerBuilder.create()
    .setDefaultTlsConfig(TlsConfig.custom()
                         .setVersionPolicy(HttpVersionPolicy.FORCE_HTTP_1)
                         .build())
    .build());

client.start();

final HttpHost target = new HttpHost("httpbin.org");
final Future<AsyncClientEndpoint> leaseFuture = client.lease(target, null);
final AsyncClientEndpoint endpoint = leaseFuture.get(30, TimeUnit.SECONDS);
try {
    
    
    final String[] requestUris = new String[] {
    
    "/", "/ip", "/user-agent", "/headers"};

    final CountDownLatch latch = new CountDownLatch(requestUris.length);
    for (final String requestUri: requestUris) {
    
    
        final SimpleHttpRequest request = SimpleRequestBuilder.get()
            .setHttpHost(target)
            .setPath(requestUri)
            .build();

        System.out.println("Executing request " + request);
        endpoint.execute(
            SimpleRequestProducer.create(request),
            SimpleResponseConsumer.create(),
            new FutureCallback<SimpleHttpResponse>() {
    
    

                @Override
                public void completed(final SimpleHttpResponse response) {
    
    
                    latch.countDown();
                    System.out.println(request + "->" + new StatusLine(response));
                    System.out.println(response.getBody());
                }

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

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

            });
    }
    latch.await();
} finally {
    
    
    endpoint.releaseAndReuse();
}

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

referencia

  1. https://hc.apache.org/httpclient-legacy/index.html

Supongo que te gusta

Origin blog.csdn.net/qq_23091073/article/details/129158796
Recomendado
Clasificación