HttpClient API常用方法

HttpClient API常用方法解释:

 

1.1 请求执行
 HttpClient最重要的功能是执行HTTP方法。执行HTTP方法涉及一个或多个HTTP请求/ HTTP响应交换,通常由HttpClient内部处理。
 用户期望提供一个请求对象来执行,并且希望HttpClient将请求发送到目标服务器返回相应的响应对象,如果执行失败则抛出异常。
 很自然,HttpClient API的主要入口点是定义上述合同的HttpClient接口。
 以下是最简单的请求执行过程的一个例子:
        CloseableHttpClient httpclient = HttpClients.createDefault();
        HttpGet httpget = new HttpGet("http://localhost/");
        CloseableHttpResponse response = httpclient.execute(httpget);
        try {
            <...>
        } finally {
        response.close();
        }

1.1.1 HTTP请求
 所有HTTP请求都有一个请求行,包括方法名称,请求URI和HTTP协议版本。
 HttpClient的支持了在HTTP / 1.1规范中定义的所有HTTP方法的框的:GET,HEAD, POST,PUT,DELETE, TRACE和OPTIONS。
 没有为每个方法类型:一个特定的类HttpGet, HttpHead,HttpPost, HttpPut,HttpDelete, HttpTrace,和HttpOptions。
 Request-URI是统一资源标识符,用于标识应用请求的资源。HTTP请求URI由协议方案,主机名,可选端口,资源路径,
 可选查询和可选片段组成。
        HttpGet httpget = new HttpGet(
            "http://www.google.com/search?hl=en&q=httpclient&btnG=Google+Search&aq=f&oq=");

HttpClient提供URIBuilder实用程序类来简化请求URI的创建和修改。
 stdout>
 http://www.google.com/search?q=httpclient&btnG=Google+Search&aq=f&oq=
        URI uri = new URIBuilder()
            .setScheme("http")
            .setHost("www.google.com")
            .setPath("/search")
            .setParameter("q", "httpclient")
            .setParameter("btnG", "Google Search")
            .setParameter("aq", "f")
            .setParameter("oq", "")
            .build();
            HttpGet httpget = new HttpGet(uri);
            System.out.println(httpget.getURI());

1.1.2 HTTP响应
 HTTP响应是在接收和解释请求消息之后由服务器发送回客户端的消息。该消息的第一行包括协议版本,后跟数字状态代码及其
 关联的文本短语。
 stdout >
 HTTP/1.1
 200
 OK
 HTTP/1.1 200 OK
 
        HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1,
        HttpStatus.SC_OK, "OK");

        System.out.println(response.getProtocolVersion());
        System.out.println(response.getStatusLine().getStatusCode());
        System.out.println(response.getStatusLine().getReasonPhrase());
        System.out.println(response.getStatusLine().toString());

1.1.3 处理消息头
 HTTP消息可以包含描述消息的属性的多个标题,例如内容长度,内容类型等。HttpClient提供了检索,添加,删除和
 枚举头文件的方法。
 stdout >
 Set-Cookie: c1=a; path=/; domain=localhost
 Set-Cookie: c2=b; path="/", c3=c; domain="localhost"
 2
 
        HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1,
            HttpStatus.SC_OK, "OK");
        response.addHeader("Set-Cookie",
            "c1=a; path=/; domain=localhost");
        response.addHeader("Set-Cookie",
            "c2=b; path=\"/\", c3=c; domain=\"localhost\"");
        Header h1 = response.getFirstHeader("Set-Cookie");
        System.out.println(h1);
        Header h2 = response.getLastHeader("Set-Cookie");
        System.out.println(h2);
        Header[] hs = response.getHeaders("Set-Cookie");
        System.out.println(hs.length);

获取给定类型的所有标头的最有效的方法是使用 HeaderIterator接口。
 stdout >
 Set-Cookie: c1=a; path=/; domain=localhost
 Set-Cookie: c2=b; path="/", c3=c; domain="localhost"
 
        HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1,
            HttpStatus.SC_OK, "OK");
        response.addHeader("Set-Cookie",
            "c1=a; path=/; domain=localhost");
        response.addHeader("Set-Cookie",
            "c2=b; path=\"/\", c3=c; domain=\"localhost\"");

        HeaderIterator it = response.headerIterator("Set-Cookie");

        while (it.hasNext()) {
            System.out.println(it.next());
        }

它还提供了方便的方法来将HTTP消息解析为单独的头元素。
 stdout >
 c1 = a
 path=/
 domain=localhost
 c2 = b
 path=/
 c3 = c
 domain=localhost
 
        HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1,
            HttpStatus.SC_OK, "OK");
        response.addHeader("Set-Cookie",
            "c1=a; path=/; domain=localhost");
        response.addHeader("Set-Cookie",
            "c2=b; path=\"/\", c3=c; domain=\"localhost\"");

        HeaderElementIterator it = new BasicHeaderElementIterator(
            response.headerIterator("Set-Cookie"));

        while (it.hasNext()) {
            HeaderElement elem = it.nextElement();
            System.out.println(elem.getName() + " = " + elem.getValue());
            NameValuePair[] params = elem.getParameters();
            for (int i = 0; i < params.length; i++) {
                System.out.println(" " + params[i]);
            }
        }

1.1.4 HTTP实体
 HTTP消息可以携带与请求或响应相关联的内容实体。实体可以在某些请求和一些响应中找到,因为它们是可选的。使用实体的请求
 被称为实体封装请求。HTTP规范定义了两个实体封装请求方法:POST和 PUT。响应通常期望包含内容实体。有例外的情况,如应对
 HEAD方法204 No Content, 304 Not Modified,205 Reset Content 响应。
 HttpClient根据其内容来源区分三种实体:
 流式传输:  内容是从流中接收到的,或者即时生成。特别地,该类别包括从HTTP响应接收到的实体。流式实体通常不可重复。
 自包含:  内容在内存中或通过独立于连接或其他实体的方式获取。自包含的实体通常是可重复的。这种类型的实体将主要用于
 封闭HTTP请求的实体。
 包装:  内容是从另一个实体获得的。
 当从HTTP响应流出内容时,此区别对于连接管理很重要。对于由应用程序创建且仅使用HttpClient发送的请求实体,流和独立的
 区别不重要。在这种情况下,建议将不可重复的实体视为流式的,将可重复的实体视为独立的。

1.1.4.1 可重复的实体
 实体可以是可重复的,这意味着它的内容可以被读取不止一次。这是唯一的可能与自包含的实体
 (如 ByteArrayEntity或 StringEntity)

1.1.4.2 使用HTTP实体
 由于实体可以表示二进制和字符内容,因此它支持字符编码(以支持后者,即字符内容)。
 当执行带有封闭内容的请求时,或者当请求成功并且使用响应主体将结果发送回客户端时,实体被创建。
 要从实体读取内容,可以通过HttpEntity#getContent()方法来检索输入流,该方法返回一个java.io.InputStream,
 或者可以向该HttpEntity#writeTo(OutputStream)方法提供输出流,一旦所有内容都被写入给定流,该方法将返回。
 当实体已经与传入消息接收,该方法 HttpEntity#getContentType()和 HttpEntity#getContentLength()方法可用于
 读取所述公共元数据,例如Content-Type与 Content-Length报头(如果可用)。由于 Content-Type标题可以包含
 text / plain或text / html等文本MIME类型的字符编码,因此该 HttpEntity#getContentEncoding()方法用于读取
 此信息。如果标题不可用,则返回长度为-1,内容类型为NULL。如果Content-Type 标题可用,Header将返回一个对象。
 当为外发消息创建实体时,该元数据必须由实体的创建者提供。
 stdout >
 Content-Type: text/plain; charset=utf-8
 17
 important message
 17

        StringEntity myEntity = new StringEntity("important message",
            ContentType.create("text/plain", "UTF-8"));

        System.out.println(myEntity.getContentType());
        System.out.println(myEntity.getContentLength());
        System.out.println(EntityUtils.toString(myEntity));
        System.out.println(EntityUtils.toByteArray(myEntity).length);

1.1.5 确保发布低级别资源
 为了确保系统资源的正确释放,必须关闭与实体或响应本身相关联的内容流
        CloseableHttpClient httpclient = HttpClients.createDefault();
        HttpGet httpget = new HttpGet("http://localhost/");
        CloseableHttpResponse response = httpclient.execute(httpget);
        try {
            HttpEntity entity = response.getEntity();
            if (entity != null) {
                InputStream instream = entity.getContent();
                try {
                //做一些有用的事情
                } finally {
                    instream.close();
                }
            }
        } finally {
            response.close();
        }

关闭内容流和关闭响应之间的区别是,前者将尝试通过占用实体内容来保持底层连接,而后者会立即关闭并丢弃连接。
 请注意,HttpEntity#writeTo(OutputStream) 一旦实体完全写出,还需要确保正确释放系统资源的方法。如果此方法
 获取一个java.io.InputStream通过调用 的实例 HttpEntity#getContent(),那么也希望在finally子句中关闭流。
 当使用流实体时,可以使用该 EntityUtils#consume(HttpEntity)方法来确保实体内容已被完全消耗,底层流已经被关闭。
 然而,可能会有情况,当仅需要检索整个响应内容的一小部分时,消耗剩余内容并使连接可重用的性能损失太高,在这种情况下,
 可以通过关闭终止内容流响应。
 连接不会重复使用,但由其持有的所有级别资源将被正确地分配。
        CloseableHttpClient httpclient = HttpClients.createDefault();
        HttpGet httpget = new HttpGet("http://localhost/");
        CloseableHttpResponse response = httpclient.execute(httpget);
        try {
            HttpEntity entity = response.getEntity();
            if (entity != null) {
                InputStream instream = entity.getContent();
                int byteOne = instream.read();
                int byteTwo = instream.read();
                //不需要休息
            }
        } finally {
            response.close();
        }

1.1.6 消费实体内容
 消费实体内容的推荐方法是使用它 HttpEntity#getContent()或 HttpEntity#writeTo(OutputStream)方法。
 HttpClient还附带了EntityUtils类,它暴露了几种静态方法,以便更容易地从实体读取内容或信息。java.io.InputStream
 可以通过使用这个类的方法,而不是直接读取,而不是直接读取字符串/字节数组中的整个内容正文。但是,EntityUtils
 除非响应实体来自受信任的HTTP服务器,并且已知其长度有限,否则强烈建议不要使用此方法。
        CloseableHttpClient httpclient = HttpClients.createDefault();
        HttpGet httpget = new HttpGet("http://localhost/");
        CloseableHttpResponse response = httpclient.execute(httpget);
        try {
            HttpEntity entity = response.getEntity();
            if (entity != null) {
                long len = entity.getContentLength();
                if (len != -1 && len < 2048) {
                    System.out.println(EntityUtils.toString(entity));
            } else {
            //流内容
            }
        }
        } finally {
            response.close();
        }

在某些情况下,可能需要多次读取实体内容。在这种情况下,实体内容必须以某种方式缓存,无论是在内存还是在磁盘上。
 最简单的方法是通过用BufferedHttpEntity类包装原始实体。这将导致将原始实体的内容读入内存缓冲区。
 在所有其他方式中,实体包装器将具有原始包装器。
        CloseableHttpResponse response = <...>
        HttpEntity entity = response.getEntity();
        if (entity != null) {
            entity = new BufferedHttpEntity(entity);
        }

1.1.7 制作实体内容
 HttpClient提供了几个类,可以通过HTTP连接高效地流出内容。这些类的实例可以与实体包围请求,如相关联POST并PUT
 以包围实体内容分成传出HTTP请求。HttpClient的提供了几个类为最常见的数据的容器,如字符串,字节数组,输入流,
 和文件:StringEntity, ByteArrayEntity, InputStreamEntity,和 FileEntity。
 请注意InputStreamEntity不可重复,因为它只能从基础数据流中读取一次。通常建议实现一个自HttpEntity包含的自定义类,
 而不是使用泛型InputStreamEntity。 FileEntity可以是一个很好的起点。
        File file = new File("somefile.txt");
        FileEntity entity = new FileEntity(file,
            ContentType.create("text/plain", "UTF-8"));

        HttpPost httppost = new HttpPost("http://localhost/action.do");
        httppost.setEntity(entity);

1.1.7.1 HTML表单
 许多应用程序需要模拟提交HTML表单的过程,例如,为了登录到Web应用程序或提交输入数据。
 HttpClient提供实体类 UrlEncodedFormEntity以方便进程。
 本UrlEncodedFormEntity实例将使用所谓的URL编码参数进行编码并生成以下内容:
 param1=value1&param2=value2
        List<NameValuePair> formparams = new ArrayList<NameValuePair>();
        formparams.add(new BasicNameValuePair("param1", "value1"));
        formparams.add(new BasicNameValuePair("param2", "value2"));
        UrlEncodedFormEntity entity = new UrlEncodedFormEntity(formparams, Consts.UTF_8);
        HttpPost httppost = new HttpPost("http://localhost/handler.do");
        httppost.setEntity(entity);

1.1.7.2 内容分块
 一般建议让HttpClient根据正在传输的HTTP消息的属性选择最合适的传输编码。然而,可以通知HttpClient,
 通过设置HttpEntity#setChunked()为true,优先选择块编码。请注意,HttpClient只会使用此标志作为提示。
 当使用不支持块编码的HTTP协议版本(如HTTP / 1.0)时,此值将被忽略。
        StringEntity entity = new StringEntity("important message",
            ContentType.create("plain/text", Consts.UTF_8));
        entity.setChunked(true);
        HttpPost httppost = new HttpPost("http://localhost/acrtion.do");
        httppost.setEntity(entity);

1.1.8 响应处理程序
 处理响应的最简单和最方便的方法是使用ResponseHandler包含该handleResponse(HttpResponse response)方法的接口。
 该方法完全可以缓解用户不必担心连接管理。使用ResponseHandlerHttpClient 时 ,无论请求执行是成功还是导致异常,
 HttpClient都将自动保证将连接释放回连接管理器。
        CloseableHttpClient httpclient = HttpClients.createDefault();
        HttpGet httpget = new HttpGet("http://localhost/json");

        ResponseHandler<MyJsonObject> rh = new ResponseHandler<MyJsonObject>() {

        @Override
        public JsonObject handleResponse(
                final HttpResponse response) throws IOException {
            StatusLine statusLine = response.getStatusLine();
            HttpEntity entity = response.getEntity();
            if (statusLine.getStatusCode() >= 300) {
                throw new HttpResponseException(
                    statusLine.getStatusCode(),
                    statusLine.getReasonPhrase());
            }
            if (entity == null) {
                throw new ClientProtocolException("Response contains no content");
            }
            Gson gson = new GsonBuilder().create();
            ContentType contentType = ContentType.getOrDefault(entity);
            Charset charset = contentType.getCharset();
            Reader reader = new InputStreamReader(entity.getContent(), charset);
            return gson.fromJson(reader, MyJsonObject.class);
            }
        };
        MyJsonObject myjson = client.execute(httpget, rh);

1.2 HttpClient接口
 HttpClient接口代表HTTP请求执行最基本的合同。它对请求执行过程没有施加任何限制或特定细节,并将连接管理,状态管理,
 认证和重定向处理的具体细节留给个别实现。这应该使得更容易使用附加功能(如响应内容缓存)来装饰接口。
 一般来说,HttpClient实现作为一个特殊目的处理程序或策略接口实现的立面,负责处理HTTP协议的特定方面,
 如重定向或身份验证处理或决定连接持久性并保持活动持续时间。这使得用户能够选择性地将这些方面的默认实现替换为具有
 特定应用程序的方面。
        ConnectionKeepAliveStrategy keepAliveStrat = new DefaultConnectionKeepAliveStrategy() {

    @Override
    public long getKeepAliveDuration(
        HttpResponse response,
        HttpContext context) {
        long keepAlive = super.getKeepAliveDuration(response, context);
        if (keepAlive == -1) {
        //如果保持活着的值,保持连接活动5秒
        //没有被服务器显式设置
        keepAlive = 5000;
        }
        return keepAlive;
        }

        };
        CloseableHttpClient httpclient = HttpClients.custom()
        .setKeepAliveStrategy(keepAliveStrat)
        .build();

1.2.1 HttpClient线程安全
 HttpClient实现预期是线程安全的。建议将此类的同一个实例重用于多个请求执行。

1.2.2 HttpClient资源释放
 当一个实例CloseableHttpClient不再需要并且即将超出范围时,与它关联的连接管理器必须通过调用
 该CloseableHttpClient#close() 方法来关闭。
        CloseableHttpClient httpclient = HttpClients.createDefault();
        try {
            <...>
        } finally {
        httpclient.close();
        }

1.3 HTTP执行上下文
 最初HTTP被设计为无状态的,响应请求的协议。然而,现实世界的应用程序通常需要通过几个逻辑相关的请求 - 响应交换
 来保持状态信息。为了使应用程序能够保持处理状态HttpClient允许在特定执行上下文(称为HTTP上下文)中执行HTTP请求。
 如果在连续请求之间重复使用相同的上下文,则多个逻辑相关请求可以参与逻辑会话。HTTP上下文功能类似于
 a java.util.Map<String, Object>。它只是一个任意命名值的集合。应用程序可以在请求执行之前填充上下文属性,
 或者在执行完成后检查上下文。
 HttpContext可以包含任意对象,因此可能不安全地在多个线程之间共享。建议每个执行线程维护自己的上下文。
 在HTTP请求执行过程中,HttpClient将以下属性添加到执行上下文中:
 HttpConnection 表示与目标服务器的实际连接的实例。
 HttpHost 表示连接目标的实例。
 HttpRoute 表示完整的连接路由的实例
 HttpRequest表示实际HTTP请求的实例。执行上下文中的最终HttpRequest对象总是表示消息的状态与
 发送到目标服务器的状态完全相同。默认HTTP / 1.0和HTTP / 1.1使用相对请求URI。然而,如果请求是通过
 非隧道模式下的代理发送的,则URI将是绝对的。
 HttpResponse 表示实际的HTTP响应。
 java.lang.Boolean 表示表示实际请求是否被完全发送到连接目标的标志的对象。
 RequestConfig 表示实际请求配置的对象。
 java.util.List<URI> 表示在请求执行过程中接收到的所有重定向位置的集合的对象。
 可以使用HttpClientContext适配器类来简化与上下文状态的分离。
        HttpContext context = <...>
        HttpClientContext clientContext = HttpClientContext.adapt(context);
        HttpHost target = clientContext.getTargetHost();
        HttpRequest request = clientContext.getRequest();
        HttpResponse response = clientContext.getResponse();
        RequestConfig config = clientContext.getRequestConfig();

表示逻辑相关会话的多个请求序列应该使用相同的HttpContext实例执行,以确保在请求之间自动传播会话上下文和状态信息。
 在以下示例中,由初始请求设置的请求配置将保留在执行上下文中,并被传播到共享相同上下文的连续请求。
        CloseableHttpClient httpclient = HttpClients.createDefault();
        RequestConfig requestConfig = RequestConfig.custom()
            .setSocketTimeout(1000)
            .setConnectTimeout(1000)
            .build();

        HttpGet httpget1 = new HttpGet("http://localhost/1");
        httpget1.setConfig(requestConfig);
        CloseableHttpResponse response1 = httpclient.execute(httpget1, context);
        try {
            HttpEntity entity1 = response1.getEntity();
        } finally {
            response1.close();
        }
        HttpGet httpget2 = new HttpGet("http://localhost/2");
        CloseableHttpResponse response2 = httpclient.execute(httpget2, context);
        try {
            HttpEntity entity2 = response2.getEntity();
        } finally {
            response2.close();
        }

1.4 HTTP协议拦截器
 HTTP协议拦截器是一个实现HTTP协议特定方面的例程。通常协议拦截器通常期望作用于输入消息的一个特定头部或一组相关头部,
 或者使用一个特定头部或一组相关头部填充传出的消息。协议拦截器还可以操纵包含消息的内容实体 - 透明内容压缩/解压缩就是
 一个很好的例子。通常这是通过使用“装饰器”模式来实现的,其中包装器实体类用于装饰原始实体。几个协议拦截器可以组合
 形成一个逻辑单元。
 协议拦截器可以通过HTTP执行上下文共享信息(如处理状态)进行协作。协议拦截器可以使用HTTP上下文来存储一个请求或
 多个连续请求的处理状态。
 通常执行拦截器的顺序并不重要,只要它们不依赖执行上下文的特定状态即可。如果协议拦截器具有相互依赖关系,因此必须
 以特定顺序执行,则应将它们按照与其预期执行顺序相同的顺序添加到协议处理器中。
 协议拦截器必须实现为线程安全。与servlet类似,协议拦截器不应该使用实例变量,除非对这些变量的访问是同步的。
 这是一个例子,说明如何使用本地上下文来持续连续请求之间的处理状态:
        CloseableHttpClient httpclient = HttpClients.custom()
            .addInterceptorLast(new HttpRequestInterceptor() {

    public void process(
            final HttpRequest request,
            final HttpContext context) throws HttpException, IOException {
        AtomicInteger count = (AtomicInteger) context.getAttribute("count");
        request.addHeader("Count", Integer.toString(count.getAndIncrement()));
    }

            })
        .build();

        AtomicInteger count = new AtomicInteger(1);
        HttpClientContext localContext = HttpClientContext.create();
        localContext.setAttribute("count", count);

        HttpGet httpget = new HttpGet("http://localhost/");
            for (int i = 0; i < 10; i++) {
            CloseableHttpResponse response = httpclient.execute(httpget, localContext);
            try {
                HttpEntity entity = response.getEntity();
            } finally {
                response.close();
            }
        }

1.5 异常处理
 HTTP协议处理器可以抛出两种类型的异常: java.io.IOException在I / O故障(例如套接字超时或套接字复位)的情况下,
 并HttpException发出HTTP故障,例如违反HTTP协议。通常I / O错误被认为是非致命和可恢复的,而HTTP协议错误被认为是致命的,
 不能自动恢复。请注意,HttpClient 实现重新抛出HttpExceptions ClientProtocolException,它是一个子类java.io.IOException。
 这使用户能够HttpClient从单个catch子句处理I / O错误和协议违规。

1.5.1 HTTP运输安全
 重要的是要了解HTTP协议不太适合所有类型的应用程序。HTTP是一种简单的面向请求/响应的协议,最初被设计为支持静态或动态
 生成的内容检索。它从来没有意图支持交易操作。例如,如果HTTP服务器成功接收和处理请求,生成响应并将状态代码发送回客户端,
 则HTTP服务器将考虑其部分合同。如果客户端由于读取超时,请求取消或系统崩溃而无法全部收到响应,服务器将不会尝试回滚事务。
 如果客户端决定重试相同的请求,服务器将不可避免地最终不止一次地执行相同的事务。在某些情况下,这可能导致应用程序数据损坏
 或应用程序状态不一致。
 即使HTTP从未被设计为支持事务处理,但是如果满足某些条件,则仍然可以将其用作任务关键应用程序的传输协议。
 为了确保HTTP传输层的安全,系统必须确保应用层上的HTTP方法的等效性。

1.5.2 幂等方法
 HTTP / 1.1规范定义了一种幂等方法
[ 方法也可以具有“幂等”的属性(除了错误或到期问题),N> 0相同请求的副作用与单个请求相同)
 换句话说,应用程序应该确保它准备好处理多次执行相同方法的含义。这可以通过例如提供唯一的事务ID和
 避免执行相同逻辑操作的其他手段来实现。
 请注意,这个问题不是HttpClient特有的。基于浏览器的应用程序受到与HTTP方法非幂等性相关的完全相同的问题。
 默认情况下,HttpClient仅假定非实体封闭方法,例如 GET并且HEAD是幂等和实体封闭方法,POST而PUT不是为了兼容性原因。

1.5.3 自动异常恢复
 默认情况下,HttpClient尝试自动从I / O异常恢复。默认的自动恢复机制仅限于一些已知是安全的异常。
 HttpClient将不会尝试从任何逻辑或HTTP协议错误(派生自HttpException类)中恢复 。
 HttpClient会自动重试那些假定为幂等的方法。
 当HTTP请求仍被传送到目标服务器(即请求尚未完全传输到服务器)时,HttpClient将自动重试那些失败的传输异常的方法。

1.5.4 请求重试处理程序
 为了启用自定义异常恢复机制,应该提供HttpRequestRetryHandler 接口的实现。
 请注意,可以使用StandardHttpRequestRetryHandler 替代默认使用的一个,以治疗由RFC-2616定义为幂的安全要求的那些
 方法来自动重试:GET, HEAD,PUT,DELETE, OPTIONS,和TRACE。
HttpRequestRetryHandler myRetryHandler = new HttpRequestRetryHandler() {

public boolean retryRequest(
        IOException exception,
        int executionCount,
        HttpContext context) {
    if (executionCount >= 5) {
        //如果超过最大重试计数,请不要重试
        return false;
    }
    if (exception instanceof InterruptedIOException) {
        // 时间到
        return false;
    }
    if (exception instanceof UnknownHostException) {
        // 未知主机
        return false;
    }
    if (exception instanceof ConnectTimeoutException) {
        // 拒绝连接
        return false;
    }
    if (exception instanceof SSLException) {
        // SSL握手异常
        return false;
    }
        HttpClientContext clientContext = HttpClientContext.adapt(context);
        HttpRequest request = clientContext.getRequest();
        boolean idempotent = !(request instanceof HttpEntityEnclosingRequest);
        if (idempotent) {
        //如果请求被认为是等幂,则重试
            return true;
        }
        return false;
    }

};
CloseableHttpClient httpclient = HttpClients.custom()
        .setRetryHandler(myRetryHandler)
        .build();

1.6 中止请求
 在某些情况下,由于目标服务器的负载过高或在客户端发出的太多并发请求,HTTP请求执行在预期时间内无法完成。
 在这种情况下,可能需要提前终止请求,并在I / O操作中解除阻塞执行线程。HttpClient执行的HTTP请求可以通过
 调用HttpUriRequest#abort()方法在执行的任何阶段中止 。该方法是线程安全的,可以从任何线程调用。
 当一个HTTP请求中止时,它的执行线程 - 即使当前在I / O操作中被阻止 - 也可以通过抛出一个 InterruptedIOException

1.7 重定向处理
 HttpClient会自动处理所有类型的重定向,除了需要用户干预的HTTP规范明确禁止的重定向之外。
 See Other(状态码303)重定向上POST和 PUT请求转换为GET所要求的HTTP规范的请求。可以使用自定义重定向策略
 来放宽对HTTP规范强加的POST方法的自动重定向的限制。
        LaxRedirectStrategy redirectStrategy = new LaxRedirectStrategy();
        CloseableHttpClient httpclient = HttpClients.custom()
            .setRedirectStrategy(redirectStrategy)
            .build();

HttpClient经常在其执行过程中重写请求消息。默认情况下,HTTP / 1.0和HTTP /1.1通常使用相对请求URI。
 同样,原始请求可能会从位置重定向到另一次。最终解释的绝对HTTP位置可以使用原始请求和上下文构建。
 该实用程序方法URIUtils#resolve可用于构建用于生成最终请求的解释的绝对URI。该方法包括来自重定向请求
 或原始请求的最后一个片段标识符。
        CloseableHttpClient httpclient = HttpClients.createDefault();
        HttpClientContext context = HttpClientContext.create();
        HttpGet httpget = new HttpGet("http://localhost:8080/");
        CloseableHttpResponse response = httpclient.execute(httpget, context);
        try {
            HttpHost target = context.getTargetHost();
            List<URI> redirectLocations = context.getRedirectLocations();
            URI location = URIUtils.resolve(httpget.getURI(), target, redirectLocations);
            System.out.println("Final HTTP location: " + location.toASCIIString());
            //预期是绝对的URI
        } finally {
            response.close();
        }

 

 

 

 

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值