如何在Apache HttpClient 4异步客户端中于请求发起前设置Bearer Token
Apache HttpClient 4 实现请求实际执行前设置Bearer Token
问题背景
使用Apache HttpClient 4异步客户端时,通过HttpRequestInterceptor设置Bearer Token,发现拦截器在提交请求阶段就全部触发,而非实际发送请求时。大量请求场景下,提前生成的Token可能在请求实际发送时过期。期望实现类似HttpClient 5的拦截器行为:在请求实际执行前触发Token设置逻辑。
测试代码如下:
public class Test { public static void main(final String[] args) { try (CloseableHttpAsyncClient httpclient = HttpAsyncClients.custom().setMaxConnTotal(2) .addInterceptorFirst(new Interceptor()).build()) { httpclient.start(); final CountDownLatch latchComplete = new CountDownLatch(10); for (int i = 0; i < 10; i++) { httpclient.execute(new HttpGet("https://www.google.com"), new CallBack(latchComplete)); } latchComplete.await(); } catch (final IOException | InterruptedException e) { e.printStackTrace(); } } static class CallBack implements FutureCallback<HttpResponse> { CountDownLatch latchComplete; CallBack(final CountDownLatch pCountDownLatch) { this.latchComplete = pCountDownLatch; } @Override public void completed(final HttpResponse pHttpResponse) { this.latchComplete.countDown(); System.out.println("completed"); } @Override public void failed(final Exception pE) { this.latchComplete.countDown(); System.out.println("failed"); } @Override public void cancelled() { this.latchComplete.countDown(); System.out.println("cancelled"); } } static class Interceptor implements HttpRequestInterceptor { @Override public void process(final HttpRequest pHttpRequest, final HttpContext pHttpContext) throws HttpException, IOException { System.out.println("Interceptor"); } } }
预期输出(拦截器与请求完成交替触发):
Interceptor Interceptor completed completed Interceptor completed Interceptor completed Interceptor completed Interceptor completed Interceptor completed Interceptor completed Interceptor completed Interceptor completed
实际输出(所有拦截器先触发,再批量完成请求):
Interceptor Interceptor Interceptor Interceptor Interceptor Interceptor Interceptor Interceptor Interceptor Interceptor completed completed completed completed completed completed completed completed completed completed
解决方案
HttpClient 4异步客户端的HttpRequestInterceptor确实会在请求提交时立即执行,而非实际发送阶段。要实现请求实际执行前设置Token,可通过**自定义HttpAsyncRequestProducer**来延迟请求的构建逻辑,具体步骤如下:
1. 自定义请求生成器
实现HttpAsyncRequestProducer接口,在generateRequest方法中添加Token设置逻辑。该方法会在请求实际准备发送(连接可用时)被调用,保证Token是最新的:
static class TokenAddingRequestProducer implements HttpAsyncRequestProducer { private final HttpGet originalRequest; public TokenAddingRequestProducer(HttpGet originalRequest) { this.originalRequest = originalRequest; } @Override public HttpContext createContext() { return new BasicHttpContext(); } @Override public HttpRequest generateRequest() throws IOException, HttpException { // 实际发送请求前获取最新Token并设置 String latestToken = getLatestBearerToken(); originalRequest.setHeader("Authorization", "Bearer " + latestToken); System.out.println("Interceptor (实际发送前设置Token)"); return originalRequest; } @Override public void requestCompleted(HttpContext context) {} @Override public void failed(Exception ex) {} @Override public void produceContent(ContentEncoder encoder, IOControl ioControl) throws IOException {} @Override public void resetRequest() throws IOException {} @Override public void close() throws IOException {} // 模拟获取最新Token的逻辑,替换为实际业务实现 private String getLatestBearerToken() { return "fresh-token-" + System.currentTimeMillis(); } }
2. 修改请求提交逻辑
将原有的HttpGet请求替换为自定义的TokenAddingRequestProducer:
// 替换原execute调用 httpclient.execute(new TokenAddingRequestProducer(new HttpGet("https://www.google.com")), new CallBack(latchComplete));
效果说明
修改后,generateRequest方法会在请求实际发送前触发,拦截器/Token设置逻辑与请求完成操作交替执行,输出符合预期,有效避免Token提前生成导致的过期问题。
内容的提问来源于stack exchange,提问作者Suzuki Yuu
相关产品推荐
相关产品推荐

