HttpClient官网学习

本文详细介绍了Apache HttpClient库的使用,包括GET和POST请求、流式传输响应、异步API、手动连接释放、请求执行拦截器、取消请求、客户端认证、代理设置、块编码POST、自定义执行上下文、线程请求执行、自定义SSL上下文和抢占式BASIC认证。示例代码涵盖了各种操作,从简单的HTTP请求到复杂的认证和连接管理。

Apache HttpComponents – HttpClient Overview

1.QuickStart

1.HTTP GET and POST requests using the HttpClient native API:

底层 HTTP 连接仍由响应对象持有,以允许直接从网络套接字流式传输响应内容。 为了确保正确释放系统资源,用户必须从 finally 子句中调用 CloseableHttpResponse#close() 。请注意,如果响应内容没有被完全消耗掉,则底层连接无法安全重用,连接管理器将关闭并丢弃。

try (CloseableHttpClient httpclient = HttpClients.createDefault()) {
// GET
// 创建GET请求
    HttpGet httpGet = new HttpGet("http://httpbin.org/get");
// 响应模型,由客户端执行发送GET请求
    try (CloseableHttpResponse response1 = httpclient.execute(httpGet)) {
// getCode getReasonPhrase
        System.out.println(response1.getCode() + " " + response1.getReasonPhrase());
//  从响应模型中获取响应实体
        HttpEntity entity1 = response1.getEntity();
        // do something useful with the response body
        // and ensure it is fully consumed
        System.out.println("响应状态为:" + response1.getStatusLine());
			if (entity1!= null) {
				System.out.println("响应内容长度为:" + entity1.getContentLength());
				System.out.println("响应内容为:" + EntityUtils.toString(entity1));
			}
		} 
        EntityUtils.consume(entity1);
    }

// POST
//    创建POST请求
    HttpPost httpPost = new HttpPost("http://httpbin.org/post");
//    将参数放入键值对类NameValuePair中,再放入集合中
    List<NameValuePair> nvps = new ArrayList<>();
    nvps.add(new BasicNameValuePair("username", "vip"));
    nvps.add(new BasicNameValuePair("password", "secret"));

    httpPost.setEntity(new UrlEncodedFormEntity(nvps));

    try (CloseableHttpResponse response2 = httpclient.execute(httpPost)) {
        System.out.println(response2.getCode() + " " + response2.getReasonPhrase());
        HttpEntity entity2 = response2.getEntity();
        // do something useful with the response body
        // and ensure it is fully consumed
        EntityUtils.consume(entity2);
    }
}

2.同一个请求用更 simpler, albeit less flexible, fluent API来实现:

fluent API将用户从在某些情况下,必须以内存中缓冲响应内容为代价来处理手动释放系统资源中释放了出来(不用手动释放资源?)

//应用上面简单的示例,写一个获得电话归属地的打印信息,结合json可以对特定信息进行抓取,这里只是将
//返回的html文本进行打印
Request.Get("http://targethost/homepage")
    .execute().returnContent();
Request.Post("http://targethost/login")
    .bodyForm(Form.form().add("username",  "vip").add("password",  "secret").build())
    .execute().returnContent();

 3.using HttpClient async API:异步

try (CloseableHttpAsyncClient httpclient = HttpAsyncClients.createDefault()) {
    // 开启client
    httpclient.start();

    // 执行request
    SimpleHttpRequest request1 = SimpleHttpRequests.get("http://httpbin.org/get");

    Future<SimpleHttpResponse> future = httpclient.execute(request1, null);
    // 等待直到response被接收
    SimpleHttpResponse response1 = future.get();
    System.out.println(request1.getRequestUri() + "->" + response1.getCode());

    // One most likely would want to use a callback for operation result
    CountDownLatch latch1 = new CountDownLatch(1);
    SimpleHttpRequest request2 = SimpleHttpRequests.get("http://httpbin.org/get");
    httpclient.execute(request2, new FutureCallback<SimpleHttpResponse>() {

        @Override
        public void completed(SimpleHttpResponse response2) {
            latch1.countDown();
            System.out.println(request2.getRequestUri() + "->" + response2.getCode());
        }

        @Override
        public void failed(Exception ex) {
            latch1.countDown();
            System.out.println(request2.getRequestUri() + "->" + ex);
        }

        @Override
        public void cancelled() {
            latch1.countDown();
            System.out.println(request2.getRequestUri() + " cancelled");
        }

    });
    latch1.await();

    // In real world one most likely would want also want to stream
    // request and response body content
    CountDownLatch latch2 = new CountDownLatch(1);
    AsyncRequestProducer producer3 = AsyncRequestBuilder.get("http://httpbin.org/get").build();
    AbstractCharResponseConsumer<HttpResponse> consumer3 = new AbstractCharResponseConsumer<HttpResponse>() {

        HttpResponse response;

        @Override
        protected void start(HttpResponse response, ContentType contentType) throws HttpException, IOException {
            this.response = response;
        }

        @Override
        protected int capacityIncrement() {
            return Integer.MAX_VALUE;
        }

        @Override
        protected void data(CharBuffer data, boolean endOfStream) throws IOException {
            // Do something useful
        }

        @Override
        protected HttpResponse buildResult() throws IOException {
            return response;
        }

        @Override
        public void releaseResources() {
        }

    };
    httpclient.execute(producer3, consumer3, new FutureCallback<HttpResponse>() {

        @Override
        public void completed(HttpResponse response3) {
            latch2.countDown();
            System.out.println(request2.getRequestUri() + "->" + response3.getCode());
        }

        @Override
        public void failed(Exception ex) {
            latch2.countDown();
            System.out.println(request2.getRequestUri() + "->" + ex);
        }

        @Override
        public void cancelled() {
            latch2.countDown();
            System.out.println(request2.getRequestUri() + " cancelled");
        }

    });
    latch2.await();

}

2. HttpClient Examples (Classic)

1.Manual connection release:手动连接释放

此示例演示如何确保在手动处理 HTTP 响应的情况下将底层 HTTP 连接释放回连接管理器。

package org.apache.hc.client5.http.examples;

import java.io.IOException;
import java.io.InputStream;

import org.apache.hc.client5.http.classic.methods.HttpGet;
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse;
import org.apache.hc.client5.http.impl.classic.HttpClients;
import org.apache.hc.core5.http.HttpEntity;

public class ClientConnectionRelease {

    public final static void main(final String[] args) throws Exception {
        try (final CloseableHttpClient httpclient = HttpClients.createDefault()) {
            final HttpGet httpget = new HttpGet("http://httpbin.org/get");
//        输出执行的HTTP请求内容:GET和请求的URI
            System.out.println("Executing request " + httpget.getMethod() + " " + httpget.getUri());
            try (final CloseableHttpResponse response = httpclient.execute(httpget)) {
                System.out.println("----------------------------------------");
//        输出状态码:200,和获取表单含义
                System.out.println(response.getCode() + " " + response.getReasonPhrase());

                // 获取响应实体: Wrapper[[Content-Type:application/json,Content-Encoding:null,Chunked:true]]
                final HttpEntity entity = response.getEntity();

                // 如果响应没有包含实体,则无需担心连接释放
                if (entity != null) {
//    entity.getContent():得到输入的流,如//org.apache.hc.core5.http.io.EofSensorInputStream@69d9c55
                    try (final InputStream inStream = entity.getContent()) {
                        inStream.read();
                        // do something useful with the response
                    } catch (final IOException ex) {
                        // 在 IOException 的情况下,连接将自动释放回连接管理器
                        throw ex;
                    }
                }
            }
        }
    }

}

2.Request execution interceptors:请求执行拦截器

此示例演示如何将自定义请求拦截器执行拦截器插入到请求执行链中。

3.Abort method:终止方法

此示例演示如何在正常完成之前中止 HTTP 请求。

package org.apache.hc.client5.http.examples;

import org.apache.hc.client5.http.classic.methods.HttpGet;
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse;
import org.apache.hc.client5.http.impl.classic.HttpClients;


public class ClientAbortMethod {

    public static void main(final String[] args) throws Exception {
        try (final CloseableHttpClient httpclient = HttpClients.createDefault()) {
            final HttpGet httpget = new HttpGet("http://httpbin.org/get");

            System.out.println("Executing request " + httpget.getMethod() + " " + httpget.getUri());
            try (final CloseableHttpResponse response = httpclient.execute(httpget)) {
                System.out.println("----------------------------------------");
                System.out.println(response.getCode() + " " + response.getReasonPhrase());
                // 不想读响应体,在请求对象上调用cancel
                httpget.cancel();
            }
        }
    }

}

4.Client authentication:客户端认证

此示例使用 HttpClient 对需要用户身份验证的目标站点(目标网站)执行 HTTP 请求。

package org.apache.hc.client5.http.examples;

import org.apache.hc.client5.http.auth.AuthScope;
import org.apache.hc.client5.http.auth.UsernamePasswordCredentials;
import org.apache.hc.client5.http.classic.methods.HttpGet;
import org.apache.hc.client5.http.impl.auth.BasicCredentialsProvider;
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse;
import org.apache.hc.client5.http.impl.classic.HttpClients;
import org.apache.hc.core5.http.io.entity.EntityUtils;


public class ClientAuthentication {

    public static void main(final String[] args) throws Exception {
//Basic认证,
        final BasicCredentialsProvider credsProvider = new BasicCredentialsProvider();
//setCredentials:设置给定身份验证范围的凭据。 给定范围的任何先前凭据都将被覆盖。
//参数:authscope—身份验证作用域,credential-给定作用域的身份验证凭据。
        credsProvider.setCredentials(
                new AuthScope("httpbin.org", 80),
                new UsernamePasswordCredentials("user", "passwd".toCharArray()));
//创建http客户端的第二种方法
        try (final CloseableHttpClient httpclient = HttpClients.custom()
                .setDefaultCredentialsProvider(credsProvider)
                .build()) {
            final HttpGet httpget = new HttpGet("http://httpbin.org/basic-auth/user/passwd");

            System.out.println("Executing request " + httpget.getMethod() + " " + httpget.getUri());
            try (final CloseableHttpResponse response = httpclient.execute(httpget)) {
                System.out.println("----------------------------------------");
                System.out.println(response.getCode() + " " + response.getReasonPhrase());
//    将响应实体转换为String类型输出
                System.out.println(EntityUtils.toString(response.getEntity()));
            }
        }
    }
}

BasicCredentialsProvider 是一个类:BasicCredentialsProvider (HttpComponents Client 4.2.1 API) (oschina.net)

创建http客户端的两种方法:

HttpClient的基本使用 - codedot - 博客园 (cnblogs.com)

/**
 * 第一种方式
 * 静态方法, 创建HTTP客户端, 返回 CloseableHttpClient 实例
 * 本质上使用 HttpClientBuilder.create().build() 创建的(即下面要介绍到的第二种方法)
 */
CloseableHttpClient httpClient = HttpClients.createDefault();
/**
 * 第二种方式:灵活可配置
 */
//调用的是 HttpClientBuilder.create();
HttpClientBuilder httpClientBuilder = HttpClients.custom();
/**
 * 使用 HttpClientBuilder 可以进行个性化配置,后面单独地详细说
 */
//创建http客户端
CloseableHttpClient httpClient = httpClientBuilder.build();

5.Request via a proxy:通过代理发送请求

此示例演示如何通过代理发送 HTTP 请求。

package org.apache.hc.client5.http.examples;

import org.apache.hc.client5.http.classic.methods.HttpGet;
import org.apache.hc.client5.http.config.RequestConfig;
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse;
import org.apache.hc.client5.http.impl.classic.HttpClients;
import org.apache.hc.core5.http.HttpHost;
import org.apache.hc.core5.http.io.entity.EntityUtils;

public class ClientExecuteProxy {

    public static void main(final String[] args)throws Exception {
        try (final CloseableHttpClient httpclient = HttpClients.createDefault()) {

            final HttpHost target = new HttpHost("https", "httpbin.org", 443);
            final HttpHost proxy = new HttpHost("http", "127.0.0.1", 8080);
//     设置代理,未设置超时处理
            final RequestConfig config = RequestConfig.custom()
                    .setProxy(proxy)
                    .build();
            final HttpGet request = new HttpGet("/get");
            request.setConfig(config);

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

            try (final CloseableHttpResponse response = httpclient.execute(target, request)) {
                System.out.println("----------------------------------------");
                System.out.println(response.getCode() + " " + response.getReasonPhrase());
//    返回的直接是JSON文件中的内容
                System.out.println(EntityUtils.toString(response.getEntity()));
            }
        }
    }

}

HttpHost:HttpHost (HttpClient 3.1 API) (apache.org)

public HttpHost(String hostname,  int port, Protocol protocol)

  • hostname- 主机名(IP 或 DNS 名称),可以为空。
  • port - 可用于设置默认协议端口
  • protocol - 协议。 值 null 可用于设置默认协议

Java中设置代理的方法:java代码中设置代理的方法 - 简书 (jianshu.com)

6.Proxy authentication:代理认证

一个简单的示例,展示了在通过身份验证代理建立隧道的安全连接上执行 HTTP 请求。

package org.apache.hc.client5.http.examples;

import org.apache.hc.client5.http.auth.AuthScope;
import org.apache.hc.client5.http.auth.UsernamePasswordCredentials;
import org.apache.hc.client5.http.classic.methods.HttpGet;
import org.apache.hc.client5.http.config.RequestConfig;
import org.apache.hc.client5.http.impl.auth.BasicCredentialsProvider;
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse;
import org.apache.hc.client5.http.impl.classic.HttpClients;
import org.apache.hc.core5.http.HttpHost;
import org.apache.hc.core5.http.io.entity.EntityUtils;


public class ClientProxyAuthentication {

    public static void main(final String[] args) throws Exception {
        final BasicCredentialsProvider credsProvider = new BasicCredentialsProvider();
        credsProvider.setCredentials(
                new AuthScope("localhost", 8888),
                new UsernamePasswordCredentials("squid", "squid".toCharArray()));
        credsProvider.setCredentials(
                new AuthScope("httpbin.org", 80),
                new UsernamePasswordCredentials("user", "passwd".toCharArray()));
        try (final CloseableHttpClient httpclient = HttpClients.custom()
                .setDefaultCredentialsProvider(credsProvider).build()) {
            final HttpHost target = new HttpHost("http", "httpbin.org", 80);
            final HttpHost proxy = new HttpHost("localhost", 8888);

            final RequestConfig config = RequestConfig.custom()
                .setProxy(proxy)
                .build();
            final HttpGet httpget = new HttpGet("/basic-auth/user/passwd");
            httpget.setConfig(config);

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

            try (final CloseableHttpResponse response = httpclient.execute(target, httpget)) {
                System.out.println("----------------------------------------");
                System.out.println(response.getCode() + " " + response.getReasonPhrase());
                System.out.println(EntityUtils.toString(response.getEntity()));
            }
        }
    }
}

7.Chunk-encoded POST:基于块编码的 POST请求

此示例显示如何使用块编码流式传输请求实体。

package org.apache.hc.client5.http.examples;

import java.io.File;
import java.io.FileInputStream;

import org.apache.hc.client5.http.classic.methods.HttpPost;
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse;
import org.apache.hc.client5.http.impl.classic.HttpClients;
import org.apache.hc.core5.http.ContentType;
import org.apache.hc.core5.http.io.entity.EntityUtils;
import org.apache.hc.core5.http.io.entity.InputStreamEntity;

public class ClientChunkEncodedPost {

    public static void main(final String[] args) throws Exception {
        if (args.length != 1)  {
            System.out.println("File path not given");
            System.exit(1);
        }
        try (final CloseableHttpClient httpclient = HttpClients.createDefault()) {
            final HttpPost httppost = new HttpPost("http://httpbin.org/post");

            final File file = new File(args[0]);
//octet:八位字节
            final InputStreamEntity reqEntity = new InputStreamEntity(
                    new FileInputStream(file), -1, ContentType.APPLICATION_OCTET_STREAM);
//在此特定实例中使用 FileEntity 类可能更合适,但我们使用更通用InputStreamEntity 来演示从任意源流式输出数据的能力
// FileEntity entity = new FileEntity(file, "binary/octet-stream");

            httppost.setEntity(reqEntity);

            System.out.println("Executing request " + httppost.getMethod() + " " + httppost.getUri());
            try (final CloseableHttpResponse response = httpclient.execute(httppost)) {
                System.out.println("----------------------------------------");
                System.out.println(response.getCode() + " " + response.getReasonPhrase());
                System.out.println(EntityUtils.toString(response.getEntity()));
            }
        }
    }

}

InputStreamEntity:InputStreamEntity (Apache HttpComponents Core HTTP/1.1 5.1.1 API)

public InputStreamEntity(InputStream inStream,
                 long length,
                 ContentType contentType)

8.Custom execution context:自定义执行上下文

演示了由自定义(custom)属性填充的本地HTTP上下文的使用

package org.apache.hc.client5.http.examples;

import java.util.List;

import org.apache.hc.client5.http.classic.methods.HttpGet;
import org.apache.hc.client5.http.cookie.BasicCookieStore;
import org.apache.hc.client5.http.cookie.Cookie;
import org.apache.hc.client5.http.cookie.CookieStore;
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse;
import org.apache.hc.client5.http.impl.classic.HttpClients;
import org.apache.hc.client5.http.protocol.HttpClientContext;
import org.apache.hc.core5.http.io.entity.EntityUtils;

public class ClientCustomContext {

    public static void main(final String[] args) throws Exception {
        try (final CloseableHttpClient httpclient = HttpClients.createDefault()) {
            // 创建 cookie 存储的本地实例
            final CookieStore cookieStore = new BasicCookieStore();

            // 创建本地 HTTP context(上下文?)
            final HttpClientContext localContext = HttpClientContext.create();
            // 将自定义 cookie 存储绑定到本地context
            localContext.setCookieStore(cookieStore);

            final HttpGet httpget = new HttpGet("http://httpbin.org/cookies");
            System.out.println("Executing request " + httpget.getMethod() + " " + httpget.getUri());

            // Pass local context as a parameter
            try (final CloseableHttpResponse response = httpclient.execute(httpget, localContext)) {
                System.out.println("----------------------------------------");
                System.out.println(response.getCode() + " " + response.getReasonPhrase());
                final List<Cookie> cookies = cookieStore.getCookies();
                for (int i = 0; i < cookies.size(); i++) {
                    System.out.println("Local cookie: " + cookies.get(i));
                }
//
                EntityUtils.consume(response.getEntity());
            }
        }
    }

}

HttpClientContext:适配器类,为 HTTP 请求执行过程中使用的常见 HttpContext 属性提供方便的类型安全设置器和获取器。HttpClientContext (Apache HttpClient 5.0.4 API)

EntityUtils:EntityUtils (Apache HttpCore 4.4.14 API)

9.Form based logon:基于表单的登录

此示例演示如何使用 HttpClient 执行基于表单的登录。

package org.apache.hc.client5.http.examples;

import java.net.URI;
import java.util.List;

import org.apache.hc.client5.http.classic.methods.HttpGet;
import org.apache.hc.client5.http.cookie.BasicCookieStore;
import org.apache.hc.client5.http.cookie.Cookie;
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse;
import org.apache.hc.client5.http.impl.classic.HttpClients;
import org.apache.hc.core5.http.ClassicHttpRequest;
import org.apache.hc.core5.http.HttpEntity;
import org.apache.hc.core5.http.io.entity.EntityUtils;
import org.apache.hc.core5.http.io.support.ClassicRequestBuilder;

public class ClientFormLogin {

    public static void main(final String[] args) throws Exception {
        final BasicCookieStore cookieStore = new BasicCookieStore();
        try (final CloseableHttpClient httpclient = HttpClients.custom()
                .setDefaultCookieStore(cookieStore)
                .build()) {
            final HttpGet httpget = new HttpGet("https://someportal/");
            try (final CloseableHttpResponse response1 = httpclient.execute(httpget)) {
                final HttpEntity entity = response1.getEntity();

                System.out.println("Login form get: " + response1.getCode() + " " + response1.getReasonPhrase());
                EntityUtils.consume(entity);

                System.out.println("Initial set of cookies:");
                final List<Cookie> cookies = cookieStore.getCookies();
                if (cookies.isEmpty()) {
                    System.out.println("None");
                } else {
                    for (int i = 0; i < cookies.size(); i++) {
                        System.out.println("- " + cookies.get(i));
                    }
                }
            }

            final ClassicHttpRequest login = ClassicRequestBuilder.post()
                    .setUri(new URI("https://someportal/"))
                    .addParameter("IDToken1", "username")
                    .addParameter("IDToken2", "password")
                    .build();
            try (final CloseableHttpResponse response2 = httpclient.execute(login)) {
                final HttpEntity entity = response2.getEntity();

                System.out.println("Login form get: " + response2.getCode() + " " + response2.getReasonPhrase());
                EntityUtils.consume(entity);

                System.out.println("Post logon cookies:");
                final List<Cookie> cookies = cookieStore.getCookies();
                if (cookies.isEmpty()) {
                    System.out.println("None");
                } else {
                    for (int i = 0; i < cookies.size(); i++) {
                        System.out.println("- " + cookies.get(i));
                    }
                }
            }
        }
    }
}
Class BasicCookieStore: BasicCookieStore (HttpComponents Client 4.2.1 API) (oschina.net)
public void addCookie(Cookie cookie):添加 HTTP cookie,替换任何现有的等效 cookie。 如果给定的 cookie 已经过期,则不会添加它,但仍将删除现有值。
public List<Cookie> getCookies():返回此 HTTP 状态当前包含的不可变 cookie 数组。

10. Threaded request execution:线程请求执行

从多个工作线程执行 HTTP 请求的示例。

package org.apache.hc.client5.http.examples;

import org.apache.hc.client5.http.classic.methods.HttpGet;
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse;
import org.apache.hc.client5.http.impl.classic.HttpClients;
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager;
import org.apache.hc.core5.http.HttpEntity;
import org.apache.hc.core5.http.io.entity.EntityUtils;
import org.apache.hc.core5.http.protocol.BasicHttpContext;
import org.apache.hc.core5.http.protocol.HttpContext;

/**
 * An example that performs GETs from multiple threads.
 *
 */
public class ClientMultiThreadedExecution {

    public static void main(final String[] args) throws Exception {
        // Create an HttpClient with the PoolingHttpClientConnectionManager.
        // 如果多个线程将使用 HttpClient,则必须使用此连接管理器。
        final PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
        cm.setMaxTotal(100);

        try (final CloseableHttpClient httpclient = HttpClients.custom()
                .setConnectionManager(cm)
                .build()) {
            // create an array of URIs to perform GETs on
            final String[] urisToGet = {
                    "http://hc.apache.org/",
                    "http://hc.apache.org/httpcomponents-core-ga/",
                    "http://hc.apache.org/httpcomponents-client-ga/",
            };

            // create a thread for each URI
            final GetThread[] threads = new GetThread[urisToGet.length];
            for (int i = 0; i < threads.length; i++) {
                final HttpGet httpget = new HttpGet(urisToGet[i]);
                threads[i] = new GetThread(httpclient, httpget, i + 1);
            }

            // start the threads
            for (final GetThread thread : threads) {
                thread.start();
            }

            // join the threads
            for (final GetThread thread : threads) {
                thread.join();
            }

        }
    }

    /**
     * A thread that performs a GET.
     */
    static class GetThread extends Thread {

        private final CloseableHttpClient httpClient;
        private final HttpContext context;
        private final HttpGet httpget;
        private final int id;

        public GetThread(final CloseableHttpClient httpClient, final HttpGet httpget, final int id) {
            this.httpClient = httpClient;
            this.context = new BasicHttpContext();
            this.httpget = httpget;
            this.id = id;
        }

        /**
         * Executes the GetMethod and prints some status information.
         */
        @Override
        public void run() {
            try {
                System.out.println(id + " - about to get something from " + httpget.getUri());
                try (CloseableHttpResponse response = httpClient.execute(httpget, context)) {
                    System.out.println(id + " - get executed");
                    // get the response body as an array of bytes
                    final HttpEntity entity = response.getEntity();
                    if (entity != null) {
                        final byte[] bytes = EntityUtils.toByteArray(entity);
                        System.out.println(id + " - " + bytes.length + " bytes read");
                    }
                }
            } catch (final Exception e) {
                System.out.println(id + " - error: " + e);
            }
        }

    }

}

11.Custom SSL context:自定义 SSL 上下文

此示例演示如何使用自定义 SSL 上下文创建安全连接。

package org.apache.hc.client5.http.examples;

import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;

import org.apache.hc.client5.http.classic.methods.HttpGet;
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse;
import org.apache.hc.client5.http.impl.classic.HttpClients;
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder;
import org.apache.hc.client5.http.io.HttpClientConnectionManager;
import org.apache.hc.client5.http.protocol.HttpClientContext;
import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory;
import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactoryBuilder;
import org.apache.hc.core5.http.io.entity.EntityUtils;
import org.apache.hc.core5.http.ssl.TLS;
import org.apache.hc.core5.ssl.SSLContexts;
import org.apache.hc.core5.ssl.TrustStrategy;

/**
 * 此示例演示如何使用自定义 SSL 上下文创建安全连接。
 */
public class ClientCustomSSL {

    public final static void main(final String[] args) throws Exception {
        // 信任标准 CA 和我们自定义策略信任的 CA
        final SSLContext sslcontext = SSLContexts.custom()
                .loadTrustMaterial(new TrustStrategy() {

                    @Override
                    public boolean isTrusted(
                            final X509Certificate[] chain,
                            final String authType) throws CertificateException {
                        final X509Certificate cert = chain[0];
                        return "CN=httpbin.org".equalsIgnoreCase(cert.getSubjectDN().getName());
                    }

                })
                .build();
        // Allow TLSv1.2 protocol only
        final SSLConnectionSocketFactory sslSocketFactory = SSLConnectionSocketFactoryBuilder.create()
                .setSslContext(sslcontext)
                .setTlsVersions(TLS.V_1_2)
                .build();
        final HttpClientConnectionManager cm = PoolingHttpClientConnectionManagerBuilder.create()
                .setSSLSocketFactory(sslSocketFactory)
                .build();
        try (CloseableHttpClient httpclient = HttpClients.custom()
                .setConnectionManager(cm)
                .build()) {

            final HttpGet httpget = new HttpGet("https://httpbin.org/");

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

            final HttpClientContext clientContext = HttpClientContext.create();
            try (CloseableHttpResponse response = httpclient.execute(httpget, clientContext)) {
                System.out.println("----------------------------------------");
                System.out.println(response.getCode() + " " + response.getReasonPhrase());
                System.out.println(EntityUtils.toString(response.getEntity()));

                final SSLSession sslSession = clientContext.getSSLSession();
                if (sslSession != null) {
                    System.out.println("SSL protocol " + sslSession.getProtocol());
                    System.out.println("SSL cipher suite " + sslSession.getCipherSuite());
                }
            }
        }
    }

}

SSLContext: SSLContext (Java Platform SE 7 ) (oracle.com)

 此类的实例表示安全套接字协议实现,它充当安全套接字工厂或 SSLEngines 的工厂。此类使用一组可选的密钥和信任管理器以及安全随机字节源(source of secure random bytes.)进行初始化。

Java 平台的每个实现都需要支持以下标准 SSLContext 协议: TLSv1

protected SSLContext(SSLContextSpi contextSpi,
          Provider provider,
          String protocol)

contextSpi:the delegate (代表?)

12.Preemptive BASIC authentication:抢占式 BASIC 身份验证 

package org.apache.hc.client5.http.examples;

import org.apache.hc.client5.http.auth.UsernamePasswordCredentials;
import org.apache.hc.client5.http.classic.methods.HttpGet;
import org.apache.hc.client5.http.impl.auth.BasicScheme;
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse;
import org.apache.hc.client5.http.impl.classic.HttpClients;
import org.apache.hc.client5.http.protocol.HttpClientContext;
import org.apache.hc.core5.http.HttpHost;
import org.apache.hc.core5.http.io.entity.EntityUtils;

/**
 * An example of how HttpClient can be customized to authenticate
 * preemptively using Basic scheme.
 * <b/>
 * Generally, preemptive authentication can be considered less
 * secure than a response to an authentication challenge
 * and therefore discouraged.
 */
public class ClientPreemptiveBasicAuthentication {

    public static void main(final String[] args) throws Exception {
        try (final CloseableHttpClient httpclient = HttpClients.createDefault()) {

            // Generate Basic scheme object and add it to the local auth cache
            final BasicScheme basicAuth = new BasicScheme();
            basicAuth.initPreemptive(new UsernamePasswordCredentials("user", "passwd".toCharArray()));

            final HttpHost target = new HttpHost("http", "httpbin.org", 80);

            // Add AuthCache to the execution context
            final HttpClientContext localContext = HttpClientContext.create();
            localContext.resetAuthExchange(target, basicAuth);

            final HttpGet httpget = new HttpGet("http://httpbin.org/hidden-basic-auth/user/passwd");

            System.out.println("Executing request " + httpget.getMethod() + " " + httpget.getUri());
            for (int i = 0; i < 3; i++) {
                try (final CloseableHttpResponse response = httpclient.execute(httpget, localContext)) {
                    System.out.println("----------------------------------------");
                    System.out.println(response.getCode() + " " + response.getReasonPhrase());
                    System.out.println(EntityUtils.toString(response.getEntity()));
                }
            }
        }
    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值