客户让我给她写个爬虫-httpClient

50 阅读3分钟

客户让我给她写个爬虫

HttpClient 详解

1. HttpClient 简介

HttpClient 是 Apache Jakarta Common 下的子项目,是一个功能强大的 HTTP 客户端工具包。它提供了:

  • 支持 HTTP/1.1 和 HTTP/2 协议
  • 支持 HTTPS
  • 支持代理服务器
  • 支持 Cookie 管理
  • 支持连接池
  • 支持请求重试
  • 支持异步请求

2. 核心组件

2.1 主要类说明

  1. HttpClient

    • 核心类,用于发送 HTTP 请求
    • 管理连接池
    • 处理请求配置
    • 管理 Cookie
  2. HttpRequest

    • 表示 HTTP 请求
    • 常用子类:
      • HttpGet:GET 请求
      • HttpPost:POST 请求
      • HttpPut:PUT 请求
      • HttpDelete:DELETE 请求
  3. HttpResponse

    • 表示 HTTP 响应
    • 包含状态码
    • 包含响应头
    • 包含响应体
  4. HttpEntity

    • 表示 HTTP 消息实体
    • 可以是请求体或响应体
    • 支持流式处理
  5. RequestConfig

    • 请求配置类
    • 设置超时
    • 设置代理
    • 设置重定向

3. 基本使用

3.1 创建 HttpClient

// 方式1:使用默认配置
CloseableHttpClient httpClient = HttpClients.createDefault();

// 方式2:自定义配置
RequestConfig config = RequestConfig.custom()
    .setConnectTimeout(5000)           // 连接超时
    .setSocketTimeout(5000)            // 读取超时
    .setConnectionRequestTimeout(5000)  // 从连接池获取连接的超时
    .build();

CloseableHttpClient httpClient = HttpClients.custom()
    .setDefaultRequestConfig(config)
    .build();

3.2 发送 GET 请求

// 创建GET请求
HttpGet request = new HttpGet("https://api.example.com/data");

// 设置请求头
request.setHeader("Content-Type", "application/json");
request.setHeader("Authorization", "Bearer token");

// 执行请求
try (CloseableHttpResponse response = httpClient.execute(request)) {
    // 获取响应状态
    int statusCode = response.getStatusLine().getStatusCode();

    // 获取响应内容
    HttpEntity entity = response.getEntity();
    String responseBody = EntityUtils.toString(entity);

    // 处理响应
    if (statusCode == 200) {
        // 处理成功响应
    }
}

3.3 发送 POST 请求

// 创建POST请求
HttpPost request = new HttpPost("https://api.example.com/data");

// 设置请求头
request.setHeader("Content-Type", "application/json");

// 设置请求体
String jsonBody = "{\"name\":\"test\",\"value\":123}";
StringEntity entity = new StringEntity(jsonBody, "UTF-8");
request.setEntity(entity);

// 执行请求
try (CloseableHttpResponse response = httpClient.execute(request)) {
    // 处理响应
}

4. 高级特性

4.1 连接池管理

// 创建连接池管理器
PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
cm.setMaxTotal(100);                // 最大连接数
cm.setDefaultMaxPerRoute(20);       // 每个路由的最大连接数

// 创建HttpClient
CloseableHttpClient httpClient = HttpClients.custom()
    .setConnectionManager(cm)
    .build();

4.2 异步请求

// 创建异步HttpClient
CloseableHttpAsyncClient httpClient = HttpAsyncClients.createDefault();
httpClient.start();

// 创建异步请求
HttpGet request = new HttpGet("https://api.example.com/data");

// 执行异步请求
Future<HttpResponse> future = httpClient.execute(request, null);
HttpResponse response = future.get(); // 等待响应

4.3 请求重试

// 创建重试策略
HttpRequestRetryHandler retryHandler = (exception, executionCount, context) -> {
    if (executionCount >= 3) {
        return false;
    }
    if (exception instanceof InterruptedIOException) {
        return false;
    }
    if (exception instanceof UnknownHostException) {
        return false;
    }
    if (exception instanceof ConnectTimeoutException) {
        return true;
    }
    if (exception instanceof SSLException) {
        return false;
    }
    return true;
};

// 创建HttpClient
CloseableHttpClient httpClient = HttpClients.custom()
    .setRetryHandler(retryHandler)
    .build();

5. 最佳实践

5.1 资源管理

  1. 使用 try-with-resources

    try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
        // 使用httpClient
    }
    
  2. 及时关闭响应

    try (CloseableHttpResponse response = httpClient.execute(request)) {
        // 处理响应
    }
    

5.2 性能优化

  1. 使用连接池

    • 避免频繁创建连接
    • 合理设置连接池大小
  2. 启用压缩

    request.setHeader("Accept-Encoding", "gzip,deflate");
    
  3. 使用持久连接

    request.setHeader("Connection", "keep-alive");
    

5.3 错误处理

  1. 超时处理

    try {
        response = httpClient.execute(request);
    } catch (ConnectTimeoutException e) {
        // 处理连接超时
    } catch (SocketTimeoutException e) {
        // 处理读取超时
    }
    
  2. 重试机制

    • 实现自定义重试策略
    • 考虑幂等性

6. 常见问题

6.1 连接超时

可能原因:

  • 网络不稳定
  • 服务器响应慢
  • 连接池配置不当

解决方案:

  • 调整超时时间
  • 实现重试机制
  • 优化连接池配置

6.2 内存泄漏

可能原因:

  • 未正确关闭资源
  • 连接池配置过大

解决方案:

  • 使用 try-with-resources
  • 及时关闭响应
  • 合理配置连接池大小

6.3 性能问题

可能原因:

  • 连接池配置不当
  • 未启用压缩
  • 请求过于频繁

解决方案:

  • 优化连接池配置
  • 启用压缩
  • 实现请求限流