zoukankan      html  css  js  c++  java
  • Part2-HttpClient官方教程-Chapter7-高级主题(Advanced topics) (HTTP Caching)

    原文链接

    7.1 自定义客户端连接

      在某些情况下,为了能够处理非标准的、不兼容的行为,可能需要自定义HTTP消息通过网络传输的方式,而不是使用HTTP参数。例如,对于web爬虫,可能有必要迫使HttpClient接受错误的响应头,以挽救消息的内容。
    通常,插入自定义消息解析器或自定义连接实现的过程涉及几个步骤:

    • 提供一个定制的LineParser / LineFormatter接口实现。根据需要实现消息解析/格式化逻辑。

      class MyLineParser extends BasicLineParser {
      
      @Override
      public Header parseHeader(
              CharArrayBuffer buffer) throws ParseException {
          try {
              return super.parseHeader(buffer);
          } catch (ParseException ex) {
              // Suppress ParseException exception
              return new BasicHeader(buffer.toString(), null);
          }
      }
      
      }
    • 提供一个自定义的HttpConnectionFactory实现。根据需要替换默认的请求写入器和/或响应解析器。

      HttpConnectionFactory<HttpRoute, ManagedHttpClientConnection> connFactory     =
          new ManagedHttpClientConnectionFactory(
              new DefaultHttpRequestWriterFactory(),
              new DefaultHttpResponseParserFactory(
                      new MyLineParser(), new DefaultHttpResponseFactory()));
      
    • 配置HttpClient以使用自定义连接工厂

      PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(
      connFactory);
      CloseableHttpClient httpclient = HttpClients.custom()
          .setConnectionManager(cm)
          .build();
      

    7.2. 有状态的HTTP连接

      虽然HTTP规范假定会话状态信息总是以HTTP cookie的形式嵌入到HTTP消息中,因此HTTP连接始终是无状态的,但这种假设在现实生活中并不总是正确的。有些情况下,HTTP连接是通过特定的用户标识或特定的安全上下文创建的,因此不能与其他用户共享,只能由相同的用户重用。这种有状态HTTP连接的示例是NTLM身份验证连接和与客户端证书身份验证的SSL连接。

    7.2.1. 用户标记处理程序

      HttpClient依赖UserTokenHandler接口来确定给定的执行上下文是否是用户特定的。如果上下文是特定于用户的,或者如果上下文不包含特定于当前用户的任何资源或细节,则该处理程序返回的令牌对象将惟一地标识当前用户。用户令牌将用于确保用户特定的资源不会被其他用户共享或重用。
      UserTokenHandler接口的默认实现使用一个主类的实例来表示HTTP连接的状态对象,如果它可以从给定的执行上下文获得。DefaultUserTokenHandler将使用基于连接的身份验证方案的用户主体,如NTLM或使用客户身份验证的SSL会话。如果两者都不可用,将返回null令牌。

    CloseableHttpClient httpclient = HttpClients.createDefault();
    HttpClientContext context = HttpClientContext.create();
    HttpGet httpget = new HttpGet("http://localhost:8080/");
    CloseableHttpResponse response = httpclient.execute(httpget, context);
    try {
        Principal principal = context.getUserToken(Principal.class);
        System.out.println(principal);
    } finally {
        response.close();
    }

    用户可以提供自定义的实现,如果默认的实现不满足他们的需要:

    UserTokenHandler userTokenHandler = new UserTokenHandler() {
    
        public Object getUserToken(HttpContext context) {
            return context.getAttribute("my-token");
        }
    
    };
    CloseableHttpClient httpclient = HttpClients.custom()
            .setUserTokenHandler(userTokenHandler)
            .build();

    7.2.2. 持续有状态连接

      请注意,只有在执行请求时,同一状态对象绑定到执行上下文时,才可以重用带有状态对象的持久连接。因此,确保同一个用户或用户令牌在请求执行之前绑定到上下文,确保使用相同的上下文来执行后续的HTTP请求是非常重要的。

    CloseableHttpClient httpclient = HttpClients.createDefault();
    HttpClientContext context1 = HttpClientContext.create();
    HttpGet httpget1 = new HttpGet("http://localhost:8080/");
    CloseableHttpResponse response1 = httpclient.execute(httpget1, context1);
    try {
        HttpEntity entity1 = response1.getEntity();
    } finally {
        response1.close();
    }
    Principal principal = context1.getUserToken(Principal.class);
    
    HttpClientContext context2 = HttpClientContext.create();
    context2.setUserToken(principal);
    HttpGet httpget2 = new HttpGet("http://localhost:8080/");
    CloseableHttpResponse response2 = httpclient.execute(httpget2, context2);
    try {
        HttpEntity entity2 = response2.getEntity();
    } finally {
        response2.close();
    }

    7.3. 使用FutureRequestExecutionService

      使用FutureRequestExecutionService,您可以安排http调用并将响应视为未来。 这是很有用的,例如, 多次调用Web服务。 使用FutureRequestExecutionService的优点是可以使用多个线程同时调度请求,设置任务超时或在不再需要响应时取消它们。
      FutureRequestExecutionService封装请求HttpRequestFutureTask,FutureTask延伸。这个类允许您取消任务,并跟踪各种度量,例如请求持续时间。

    7.3.1. 创建FutureRequestExecutionService

      futureRequestExecutionService需要任何现有的httpClient实例的构造函数和一个ExecutorService实例。在配置两者时,最重要的是将最大连接数与将要使用的线程数保持一致。当线程多于连接时,连接可能会开始超时,因为没有可用的连接。当有更多的连接比线程,futureRequestExecutionService不会使用它们.

    HttpClient httpClient = HttpClientBuilder.create().setMaxConnPerRoute(5).build();
    ExecutorService executorService = Executors.newFixedThreadPool(5);
    FutureRequestExecutionService futureRequestExecutionService =
        new FutureRequestExecutionService(httpClient, executorService);

    7.3.2. 调度请求

      要安排一个请求,只需提供HttpUriRequest、HttpContext和ResponseHandler。因为请求是由executor服务处理的,所以ResponseHandler是强制的。

    private final class OkidokiHandler implements ResponseHandler<Boolean> {
        public Boolean handleResponse(
                final HttpResponse response) throws ClientProtocolException, IOException {
            return response.getStatusLine().getStatusCode() == 200;
        }
    }
    
    HttpRequestFutureTask<Boolean> task = futureRequestExecutionService.execute(
        new HttpGet("http://www.google.com"), HttpClientContext.create(),
        new OkidokiHandler());
    // blocks until the request complete and then returns true if you can connect to Google
    boolean ok=task.get();

    7.3.3. 取消任务

      计划的任务可能被取消。如果任务还没有执行,但只是排队等待执行,那么它将永远不会执行。如果它正在执行,而mayInterruptIfRunning参数被设置为true,那么将会在请求中调用abort()方法;否则,响应将被简单地忽略,但是请求将被允许正常完成。任何后续的任务调用都将抛出IllegalStateException异常。应该注意的是,取消任务只会释放客户端资源。实际上,请求可以在服务器端正常地处理。

    task.cancel(true)
    task.get() // throws an Exception

    7.3.4. 回调

      除了手动调用task.get()之外,您还可以使用FutureCallback实例在请求完成时获取回调。 这与HttpAsyncClient中使用的接口相同.

    private final class MyCallback implements FutureCallback<Boolean> {
    
        public void failed(final Exception ex) {
            // do something
        }
    
        public void completed(final Boolean result) {
            // do something
        }
    
        public void cancelled() {
            // do something
        }
    }
    
    HttpRequestFutureTask<Boolean> task = futureRequestExecutionService.execute(
        new HttpGet("http://www.google.com"), HttpClientContext.create(),
        new OkidokiHandler(), new MyCallback());

    7.3.5. 度量

      FutureRequestExecutionService通常用于执行大量Web服务调用的应用程序。 为了便于例如 监控或配置调优,FutureRequestExecutionService会跟踪几个指标。
    每个HttpRequestFutureTask都提供了获取任务计划,开始和结束时间的方法。 此外,请求和任务持续时间也可用。 这些指标汇总在FutureRequestExecutionMetrics实例中的FutureRequestExecutionService中,该实例可通过FutureRequestExecutionService.metrics()进行访问。

    task.scheduledTime() // returns the timestamp the task was scheduled
    task.startedTime() // returns the timestamp when the task was started
    task.endedTime() // returns the timestamp when the task was done executing
    task.requestDuration // returns the duration of the http request
    task.taskDuration // returns the duration of the task from the moment it was scheduled
    
    FutureRequestExecutionMetrics metrics = futureRequestExecutionService.metrics()
    metrics.getActiveConnectionCount() // currently active connections
    metrics.getScheduledConnectionCount(); // currently scheduled connections
    metrics.getSuccessfulConnectionCount(); // total number of successful requests
    metrics.getSuccessfulConnectionAverageDuration(); // average request duration
    metrics.getFailedConnectionCount(); // total number of failed tasks
    metrics.getFailedConnectionAverageDuration(); // average duration of failed tasks
    metrics.getTaskCount(); // total number of tasks scheduled
    metrics.getRequestCount(); // total number of requests
    metrics.getRequestAverageDuration(); // average request duration
    metrics.getTaskAverageDuration(); // average task duration
  • 相关阅读:
    UI Shader:平面特效火
    !!! 注意区分 lua table 变量的【原地修改】与【重新赋值】
    四舍五入 :先加 0.5, 再向下取整
    预乘α
    【 pivot 】 用代码动态设置 pivot 会导致UI 立即发生位移!
    【DrawCall】 unity 动态合批被打断的规律总结
    Text 首行缩进
    SVN 不小心上传,想要回撤提交,同时还要想保存本地的更改
    unity中打开文件夹选择文件返回文件的路径
    复制文件到指定目录
  • 原文地址:https://www.cnblogs.com/snailclimb/p/9086442.html
Copyright © 2011-2022 走看看