Apache HttpClient 4.5.x 学习总结五:HTTP execution context(HTTP执行上下文)

翻译:

1.3. HTTP 执行上下文
HTTP 设计初衷是无状态的请求-响应协议,但实际应用常需在多个逻辑关联的请求间保持状态信息。为此,HttpClient 允许在特定执行上下文(HTTP Context)中执行请求。通过在连续请求间复用相同上下文,多个逻辑关联的请求可组成逻辑会话。HTTP 上下文功能类似 java.util.Map<String, Object>,本质是命名值的集合。应用可在请求执行前填充上下文属性,或在执行后检查上下文。

注意:HttpContext 可包含任意对象,非线程安全。建议每个执行线程维护独立上下文。

HttpClient 在请求执行期间自动注入以下上下文属性:

  • HttpConnection:表示到目标服务器的实际连接
  • HttpHost:表示连接目标
  • HttpRoute:表示完整连接路由
  • HttpRequest:实际 HTTP 请求(最终发送状态)
  • HttpResponse:实际 HTTP 响应
  • Boolean:标记请求是否已完整传输到目标
  • RequestConfig:实际请求配置
  • List<URI>:请求执行中接收的所有重定向位置

可使用 HttpClientContext 工具类简化上下文操作:

HttpContext context = <...>;
HttpClientContext clientContext = HttpClientContext.adapt(context); // 上下文适配
HttpHost target = clientContext.getTargetHost();     // 获取目标主机
HttpRequest request = clientContext.getRequest();    // 获取实际请求
RequestConfig config = clientContext.getRequestConfig(); // 获取请求配置

逻辑会话实践
属于同一逻辑会话的请求序列应共享 HttpContext 实例,确保上下文状态自动传播:

CloseableHttpClient httpclient = HttpClients.createDefault();
// 初始配置(设置超时)
RequestConfig requestConfig = RequestConfig.custom()
        .setSocketTimeout(1000)
        .setConnectTimeout(1000)
        .build();

// 请求1:注入配置
HttpGet httpget1 = new HttpGet("http://localhost/1");
httpget1.setConfig(requestConfig);
// 执行请求并传递上下文
CloseableHttpResponse response1 = httpclient.execute(httpget1, context); 
try { /* 处理响应1 */ } finally { response1.close(); }

// 请求2:自动继承相同上下文中的配置!
HttpGet httpget2 = new HttpGet("http://localhost/2");
CloseableHttpResponse response2 = httpclient.execute(httpget2, context); 
try { /* 处理响应2 */ } finally { response2.close(); }

深度解读:

1. 上下文的核心价值

graph LR A[无状态协议] --> B[业务需状态保持] B --> C[解决方案] C --> D1(Cookie) C --> D2(Session) C --> D3(HttpContext) D3 --> E[跨请求共享数据]
  • 本质:在无状态协议上构建有状态会话
  • 典型场景:登录态保持、连续API调用、跨请求配置传递

2. 线程安全陷阱与规避

  • 危险操作
    // 错误!多线程共享同一上下文
    public static HttpContext SHARED_CTX = new BasicHttpContext(); 
    
  • 正确姿势
    // 每个线程独立上下文 (如Spring@Scope("request"))
    ThreadLocal<HttpContext> threadCtx = new ThreadLocal<>();
    

3. 自动注入的黄金八属性

属性 关键信息 应用场景
HttpConnection 底层TCP连接对象 监控连接状态
HttpRoute 完整路由路径(含代理) 分析网络拓扑
List<URI> 重定向轨迹 调试跳转异常
RequestConfig 超时/代理等配置 配置继承机制的核心

4. 配置传播机制解析

// 初始请求设置配置
httpget1.setConfig(customConfig); // (1) 显式设置
client.execute(httpget1, context); 

// 后续请求自动继承
client.execute(httpget2, context); // (2) 从context读取配置
  • 实现原理
    首次执行时将 RequestConfig 存入上下文,后续请求通过 HttpClientContext.getRequestConfig() 优先使用上下文配置

5. 企业级应用实践

  • 用户会话保持
    // 登录后存储token到上下文
    context.setAttribute("AUTH_TOKEN", extractToken(response)); 
    
    // 后续请求自动携带token
    httpGet.addHeader("Authorization", 
        context.getAttribute("AUTH_TOKEN").toString());
    
  • 全链路监控
    // 获取连接创建时间戳
    long connectStart = (Long)context.getAttribute("CONNECT_START"); 
    // 计算真实网络耗时
    long latency = System.currentTimeMillis() - connectStart; 
    

警示:上下文生命周期通常与业务会话绑定,切忌将其存入静态变量或长时间存活的Bean(易引发内存泄漏)。

posted @ 2025-07-22 17:23  hqq的进阶日记  阅读(16)  评论(0)    收藏  举报