如何同时记录HttpRequest与HttpResponse并获取拦截器添加的请求信息?
Apache HttpClient 同时记录处理后的请求与响应日志方案
要解决拦截器修改请求后无法获取最终请求对象的问题,核心思路是利用HttpClient的**请求上下文(HttpContext)**存储经过所有拦截器处理后的请求,再在响应拦截器中取出该请求与响应一起完成日志记录。具体实现步骤如下:
1. 定义请求拦截器,存储处理后的请求
创建一个请求拦截器,在所有内置拦截器处理完请求后,将最终的请求对象存入上下文:
public class RequestStorageInterceptor implements HttpRequestInterceptor { // 上下文存储键,自定义即可 public static final String PROCESSED_REQUEST_KEY = "final_http_request"; @Override public void process(HttpRequest request, HttpContext context) throws HttpException, IOException { // 将处理完毕的请求存入上下文 context.setAttribute(PROCESSED_REQUEST_KEY, request); } }
2. 定义响应拦截器,结合请求与响应日志
创建响应拦截器,从上下文中取出之前存储的最终请求,调用你的日志方法完成联合记录:
public class RequestResponseLoggingInterceptor implements HttpResponseInterceptor { private final HttpClientLogger httpClientLogger; public RequestResponseLoggingInterceptor(HttpClientLogger logger) { this.httpClientLogger = logger; } @Override public void process(HttpResponse response, HttpContext context) throws HttpException, IOException { // 从上下文获取处理后的请求 HttpRequest processedRequest = (HttpRequest) context.getAttribute(RequestStorageInterceptor.PROCESSED_REQUEST_KEY); if (processedRequest != null) { // 同时传入请求和响应记录日志 httpClientLogger.logRequestResponse(processedRequest, response); } } }
3. 修改HttpClient构建逻辑,添加拦截器
在构建HttpClient时,将上述两个拦截器加入构建器:
@Override public HttpResponse send(String method, String path, Map<String, String> headers, HttpEntity httpEntity) throws IOException { HttpUriRequest request = getHttpUriRequest(method, path, headers, httpEntity); // 构建HttpClient时添加拦截器 try (CloseableHttpClient httpClient = httpClientBuilder .addInterceptorLast(new RequestStorageInterceptor()) // 最后执行请求拦截器,确保存入最终请求 .addInterceptorFirst(new RequestResponseLoggingInterceptor(httpClientLogger)) // 优先执行响应拦截器 .build()) { return httpClient.execute(request); } }
方案说明
- 请求拦截器使用
addInterceptorLast:保证它在所有内置拦截器(比如添加默认头、处理编码的拦截器)之后执行,存入的是实际发送给服务器的最终请求对象。 - 响应拦截器使用
addInterceptorFirst:确保在其他响应拦截器处理之前完成日志记录,避免响应被修改后日志失真。 - 通过
HttpContext传递请求对象:完全规避了HttpClient内部复制请求导致的原始对象与实际请求不一致的问题,拿到的请求是经过所有拦截器处理后的完整版本。
内容的提问来源于stack exchange,提问作者Miss Skooter
相关产品推荐
相关产品推荐

