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
  • 相关阅读:
    PAT 甲级 1027 Colors in Mars
    PAT 甲级 1026 Table Tennis(模拟)
    PAT 甲级 1025 PAT Ranking
    PAT 甲级 1024 Palindromic Number
    PAT 甲级 1023 Have Fun with Numbers
    PAT 甲级 1021 Deepest Root (并查集,树的遍历)
    Java实现 蓝桥杯VIP 算法训练 无权最长链
    Java实现 蓝桥杯VIP 算法训练 无权最长链
    Java实现 蓝桥杯 算法提高 抽卡游戏
    Java实现 蓝桥杯 算法提高 抽卡游戏
  • 原文地址:https://www.cnblogs.com/snailclimb/p/9086442.html
Copyright © 2011-2022 走看看