前言

在前面的文章中,我们已经实现了框架的核心功能:注解系统、动态代理和 HTTP 客户端。现在我们要为框架添加一个重要的特性 —— 拦截器机制。

拦截器是框架扩展性的核心,它允许用户在 HTTP 请求的生命周期中插入自定义逻辑,实现诸如:

  • 统一的认证处理
  • 请求和响应日志记录
  • 性能监控和统计
  • 缓存机制
  • 重试逻辑
  • 请求参数加密
  • 响应数据解密

一个好的拦截器机制应该具备:

  • 易于使用:简单的接口定义
  • 功能完整:覆盖请求生命周期的各个阶段
  • 灵活配置:支持全局、类级别和方法级别配置
  • 链式执行:支持多个拦截器的有序执行
  • 异常处理:完善的异常处理机制

拦截器设计原理

AOP(面向切面编程)思想

拦截器机制本质上是 AOP 的一种实现,它将横切关注点(如日志、安全、事务等)从业务逻辑中分离出来:

业务逻辑:获取用户信息
横切关注点:
  - 认证检查
  - 日志记录
  - 性能监控
  - 异常处理

责任链模式

拦截器的执行采用责任链模式,每个拦截器都有机会处理请求,并决定是否继续传递给下一个拦截器:

请求 → 拦截器1 → 拦截器2 → 拦截器3 → HTTP客户端 → 响应
     ←         ←         ←         ←              ←

生命周期钩子

拦截器在 HTTP 请求的不同阶段提供钩子方法:

  1. preHandle:请求发送前
  2. postHandle:响应接收后
  3. afterThrowing:异常发生时

核心接口设计

RequestInterceptor 接口

package io.github.nemoob.httpclient;

/**
 * 请求拦截器接口
 * 定义了HTTP请求生命周期中的拦截点
 */
public interface RequestInterceptor {
    
    /**
     * 请求前拦截
     * 在HTTP请求发送前调用,可以修改请求参数、添加请求头等
     * 
     * @param context 请求上下文
     * @throws Exception 处理异常
     */
    void preHandle(RequestContext context) throws Exception;
    
    /**
     * 响应后拦截
     * 在HTTP响应接收后调用,可以处理响应数据、记录日志等
     * 
     * @param context 请求上下文
     * @throws Exception 处理异常
     */
    void postHandle(RequestContext context) throws Exception;
    
    /**
     * 异常处理
     * 在请求过程中发生异常时调用,可以进行异常处理、重试等
     * 
     * @param context 请求上下文
     * @param ex 异常对象
     * @throws Exception 处理异常
     */
    void afterThrowing(RequestContext context, Exception ex) throws Exception;
}

抽象基类实现

为了简化拦截器的实现,我们提供一个抽象基类:

package io.github.nemoob.httpclient;

/**
 * 请求拦截器抽象基类
 * 提供默认的空实现,子类只需要重写需要的方法
 */
public abstract class AbstractRequestInterceptor implements RequestInterceptor {
    
    @Override
    public void preHandle(RequestContext context) throws Exception {
        // 默认空实现
    }
    
    @Override
    public void postHandle(RequestContext context) throws Exception {
        // 默认空实现
    }
    
    @Override
    public void afterThrowing(RequestContext context, Exception ex) throws Exception {
        // 默认空实现
    }
}

内置拦截器实现

1. 日志拦截器

package io.github.nemoob.httpclient;

import java.util.logging.Logger;

/**
 * 日志拦截器
 * 记录HTTP请求和响应的详细信息
 */
public class LoggingInterceptor extends AbstractRequestInterceptor {
    
    private static final Logger logger = Logger.getLogger(LoggingInterceptor.class.getName());
    
    private boolean logHeaders = true;
    private boolean logBody = true;
    private int maxBodyLength = 1024;
    
    public LoggingInterceptor() {}
    
    public LoggingInterceptor(boolean logHeaders, boolean logBody, int maxBodyLength) {
        this.logHeaders = logHeaders;
        this.logBody = logBody;
        this.maxBodyLength = maxBodyLength;
    }
    
    @Override
    public void preHandle(RequestContext context) throws Exception {
        Request request = context.getRequest();
        if (request == null) {
            return;
        }
        
        StringBuilder logMessage = new StringBuilder();
        logMessage.append("HTTP Request: ")
                  .append(request.getMethod())
                  .append(" ")
                  .append(request.getUrl());
        
        // 记录请求头
        if (logHeaders && request.getHeaders() != null && !request.getHeaders().isEmpty()) {
            logMessage.append("nHeaders: ");
            request.getHeaders().forEach((key, value) -> 
                logMessage.append("n  ").append(key).append(": ").append(value)
            );
        }
        
        // 记录请求体
        if (logBody && request.getBody() != null) {
            String body = request.getBody().toString();
            if (body.length() > maxBodyLength) {
                body = body.substring(0, maxBodyLength) + "... (truncated)";
            }
            logMessage.append("nBody: ").append(body);
        }
        
        logger.info(logMessage.toString());
    }
    
    @Override
    public void postHandle(RequestContext context) throws Exception {
        Response response = context.getResponse();
        if (response == null) {
            return;
        }
        
        long duration = context.getEndTime() - context.getStartTime();
        
        StringBuilder logMessage = new StringBuilder();
        logMessage.append("HTTP Response: ")
                  .append(response.getStatusCode())
                  .append(" (")
                  .append(duration)
                  .append("ms)");
        
        // 记录响应头
        if (logHeaders && response.getHeaders() != null && !response.getHeaders().isEmpty()) {
            logMessage.append("nHeaders: ");
            response.getHeaders().forEach((key, value) -> 
                logMessage.append("n  ").append(key).append(": ").append(value)
            );
        }
        
        // 记录响应体
        if (logBody) {
            String body = response.getBodyAsString();
            if (body != null) {
                if (body.length() > maxBodyLength) {
                    body = body.substring(0, maxBodyLength) + "... (truncated)";
                }
                logMessage.append("nBody: ").append(body);
            }
        }
        
        logger.info(logMessage.toString());
    }
    
    @Override
    public void afterThrowing(RequestContext context, Exception ex) throws Exception {
        long duration = System.currentTimeMillis() - context.getStartTime();
        
        logger.severe(String.format("HTTP Request failed after %dms: %s %s - %s", 
            duration,
            context.getRequest() != null ? context.getRequest().getMethod() : "UNKNOWN",
            context.getRequest() != null ? context.getRequest().getUrl() : "UNKNOWN",
            ex.getMessage()
        ));
    }
    
    // Getter and Setter methods
    public boolean isLogHeaders() {
        return logHeaders;
    }
    
    public void setLogHeaders(boolean logHeaders) {
        this.logHeaders = logHeaders;
    }
    
    public boolean isLogBody() {
        return logBody;
    }
    
    public void setLogBody(boolean logBody) {
        this.logBody = logBody;
    }
    
    public int getMaxBodyLength() {
        return maxBodyLength;
    }
    
    public void setMaxBodyLength(int maxBodyLength) {
        this.maxBodyLength = maxBodyLength;
    }
}

2. 认证拦截器

package io.github.nemoob.httpclient;

/**
 * 认证拦截器
 * 自动为请求添加认证信息
 */
public class AuthInterceptor extends AbstractRequestInterceptor {
    
    private final String token;
    private final String headerName;
    private final String tokenPrefix;
    
    public AuthInterceptor(String token) {
        this(token, "Authorization", "Bearer ");
    }
    
    public AuthInterceptor(String token, String headerName, String tokenPrefix) {
        this.token = token;
        this.headerName = headerName;
        this.tokenPrefix = tokenPrefix;
    }
    
    @Override
    public void preHandle(RequestContext context) throws Exception {
        Request request = context.getRequest();
        if (request == null) {
            return;
        }
        
        // 如果请求中已经有认证头,则不覆盖
        if (request.getHeaders().containsKey(headerName)) {
            return;
        }
        
        // 添加认证头
        String authValue = tokenPrefix + token;
        request.getHeaders().put(headerName, authValue);
    }
}

3. 重试拦截器

package io.github.nemoob.httpclient;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

/**
 * 重试拦截器
 * 在请求失败时自动重试
 */
public class RetryInterceptor extends AbstractRequestInterceptor {
    
    private final int maxRetries;
    private final long retryDelay;
    private final Set<Integer> retryableStatusCodes;
    private final Set<Class<? extends Exception>> retryableExceptions;
    
    public RetryInterceptor() {
        this(3, 1000);
    }
    
    public RetryInterceptor(int maxRetries, long retryDelay) {
        this.maxRetries = maxRetries;
        this.retryDelay = retryDelay;
        
        // 默认可重试的状态码
        this.retryableStatusCodes = new HashSet<>(Arrays.asList(500, 502, 503, 504, 408, 429));
        
        // 默认可重试的异常类型
        this.retryableExceptions = new HashSet<>(Arrays.asList(
            java.net.SocketTimeoutException.class,
            java.net.ConnectException.class,
            java.io.IOException.class
        ));
    }
    
    @Override
    public void afterThrowing(RequestContext context, Exception ex) throws Exception {
        // 获取当前重试次数
        Integer retryCount = (Integer) context.getAttribute("retryCount");
        if (retryCount == null) {
            retryCount = 0;
        }
        
        // 检查是否可以重试
        if (retryCount >= maxRetries || !isRetryable(ex)) {
            throw ex;
        }
        
        // 增加重试次数
        context.setAttribute("retryCount", retryCount + 1);
        
        // 等待后重试
        try {
            Thread.sleep(retryDelay * (retryCount + 1)); // 指数退避
        } catch (InterruptedException ie) {
            Thread.currentThread().interrupt();
            throw ex;
        }
        
        // 重新执行请求
        try {
            HttpClient client = context.getClient();
            ResponseHandler<?> handler = createResponseHandler(context.getMethod());
            Object result = client.execute(context.getRequest(), handler);
            
            // 设置响应到上下文
            if (result instanceof Response) {
                context.setResponse((Response) result);
            }
            
        } catch (Exception retryEx) {
            // 递归调用,继续重试逻辑
            afterThrowing(context, retryEx);
        }
    }
    
    /**
     * 判断异常是否可重试
     */
    private boolean isRetryable(Exception ex) {
        // 检查异常类型
        for (Class<? extends Exception> retryableType : retryableExceptions) {
            if (retryableType.isInstance(ex)) {
                return true;
            }
        }
        
        // 检查HTTP状态码
        if (ex instanceof HttpException) {
            HttpException httpEx = (HttpException) ex;
            return retryableStatusCodes.contains(httpEx.getStatusCode());
        }
        
        return false;
    }
    
    /**
     * 创建响应处理器(简化实现)
     */
    private ResponseHandler<?> createResponseHandler(java.lang.reflect.Method method) {
        // 这里应该根据方法返回类型创建合适的处理器
        // 为了简化,返回一个通用的处理器
        return new JsonResponseHandler<>(Object.class, HttpClientFactory.getObjectMapper());
    }
}

4. 性能监控拦截器

package io.github.nemoob.httpclient;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.LongAdder;

/**
 * 性能监控拦截器
 * 收集HTTP请求的性能统计信息
 */
public class MetricsInterceptor extends AbstractRequestInterceptor {
    
    // 请求计数器
    private final ConcurrentHashMap<String, LongAdder> requestCounts = new ConcurrentHashMap<>();
    
    // 响应时间统计
    private final ConcurrentHashMap<String, AtomicLong> totalResponseTimes = new ConcurrentHashMap<>();
    
    // 错误计数器
    private final ConcurrentHashMap<String, LongAdder> errorCounts = new ConcurrentHashMap<>();
    
    @Override
    public void preHandle(RequestContext context) throws Exception {
        // 记录请求开始时间(如果还没有记录)
        if (context.getStartTime() == 0) {
            context.setAttribute("startTime", System.currentTimeMillis());
        }
        
        // 增加请求计数
        String methodUrl = getMethodUrl(context);
        requestCounts.computeIfAbsent(methodUrl, k -> new LongAdder()).increment();
    }
    
    @Override
    public void postHandle(RequestContext context) throws Exception {
        long endTime = System.currentTimeMillis();
        long startTime = (Long) context.getAttribute("startTime");
        long duration = endTime - startTime;
        
        // 记录响应时间
        String methodUrl = getMethodUrl(context);
        totalResponseTimes.computeIfAbsent(methodUrl, k -> new AtomicLong()).addAndGet(duration);
    }
    
    @Override
    public void afterThrowing(RequestContext context, Exception ex) throws Exception {
        // 增加错误计数
        String methodUrl = getMethodUrl(context);
        errorCounts.computeIfAbsent(methodUrl, k -> new LongAdder()).increment();
    }
    
    /**
     * 获取方法URL标识
     */
    private String getMethodUrl(RequestContext context) {
        Request request = context.getRequest();
        if (request == null) {
            return "UNKNOWN";
        }
        return request.getMethod() + " " + request.getUrl();
    }
    
    /**
     * 获取性能统计信息
     */
    public MetricsReport getMetrics() {
        MetricsReport report = new MetricsReport();
        
        for (String methodUrl : requestCounts.keySet()) {
            long requestCount = requestCounts.get(methodUrl).sum();
            long totalTime = totalResponseTimes.getOrDefault(methodUrl, new AtomicLong()).get();
            long errorCount = errorCounts.getOrDefault(methodUrl, new LongAdder()).sum();
            
            double avgResponseTime = requestCount > 0 ? (double) totalTime / requestCount : 0;
            double errorRate = requestCount > 0 ? (double) errorCount / requestCount : 0;
            
            report.addMetric(methodUrl, requestCount, avgResponseTime, errorRate);
        }
        
        return report;
    }
    
    /**
     * 性能报告类
     */
    public static class MetricsReport {
        private final ConcurrentHashMap<String, Metric> metrics = new ConcurrentHashMap<>();
        
        public void addMetric(String methodUrl, long requestCount, double avgResponseTime, double errorRate) {
            metrics.put(methodUrl, new Metric(requestCount, avgResponseTime, errorRate));
        }
        
        public Metric getMetric(String methodUrl) {
            return metrics.get(methodUrl);
        }
        
        public ConcurrentHashMap<String, Metric> getAllMetrics() {
            return metrics;
        }
        
        @Override
        public String toString() {
            StringBuilder sb = new StringBuilder("Performance Metrics:n");
            metrics.forEach((methodUrl, metric) -> {
                sb.append(String.format("%s: requests=%d, avgTime=%.2fms, errorRate=%.2f%%n",
                    methodUrl, metric.requestCount, metric.avgResponseTime, metric.errorRate * 100));
            });
            return sb.toString();
        }
    }
    
    /**
     * 单个指标类
     */
    public static class Metric {
        public final long requestCount;
        public final double avgResponseTime;
        public final double errorRate;
        
        public Metric(long requestCount, double avgResponseTime, double errorRate) {
            this.requestCount = requestCount;
            this.avgResponseTime = avgResponseTime;
            this.errorRate = errorRate;
        }
    }
}

拦截器配置机制

1. 全局拦截器配置

// 在HttpClientFactory中添加全局拦截器管理
public class HttpClientFactory {
    private static final List<RequestInterceptor> globalInterceptors = new ArrayList<>();
    
    /**
     * 添加全局拦截器
     */
    public static void addGlobalInterceptor(RequestInterceptor interceptor) {
        globalInterceptors.add(interceptor);
    }
    
    /**
     * 移除全局拦截器
     */
    public static void removeGlobalInterceptor(RequestInterceptor interceptor) {
        globalInterceptors.remove(interceptor);
    }
    
    /**
     * 清空全局拦截器
     */
    public static void clearGlobalInterceptors() {
        globalInterceptors.clear();
    }
    
    /**
     * 获取全局拦截器列表
     */
    public static List<RequestInterceptor> getGlobalInterceptors() {
        return new ArrayList<>(globalInterceptors);
    }
}

2. 类级别拦截器配置

通过 @Interceptor 注解配置:

@HttpClient("https://api.example.com")
@Interceptor({LoggingInterceptor.class, AuthInterceptor.class})
public interface UserService {
    @GET("/users")
    List<User> getUsers();
}

3. 方法级别拦截器配置

通过 @MethodInterceptor 注解配置:

@HttpClient("https://api.example.com")
public interface UserService {
    @GET("/users")
    @MethodInterceptor({MetricsInterceptor.class})
    List<User> getUsers();
    
    @POST("/users")
    @MethodInterceptor({LoggingInterceptor.class, RetryInterceptor.class})
    User createUser(@Body User user);
}

拦截器执行机制

执行顺序

拦截器的执行遵循以下顺序:

  1. preHandle 阶段:全局拦截器 → 类级别拦截器 → 方法级别拦截器
  2. HTTP 请求执行
  3. postHandle 阶段:方法级别拦截器 → 类级别拦截器 → 全局拦截器(逆序)
  4. afterThrowing 阶段:所有拦截器(正序)

拦截器链实现

public class InterceptorChain {
    private final List<RequestInterceptor> interceptors;
    
    public InterceptorChain(List<RequestInterceptor> interceptors) {
        this.interceptors = new ArrayList<>(interceptors);
    }
    
    /**
     * 执行前置拦截器
     */
    public void executePreHandle(RequestContext context) throws Exception {
        for (RequestInterceptor interceptor : interceptors) {
            interceptor.preHandle(context);
        }
    }
    
    /**
     * 执行后置拦截器(逆序)
     */
    public void executePostHandle(RequestContext context) throws Exception {
        for (int i = interceptors.size() - 1; i >= 0; i--) {
            try {
                interceptors.get(i).postHandle(context);
            } catch (Exception e) {
                // 记录日志但不中断其他拦截器的执行
                System.err.println("PostHandle interceptor failed: " + e.getMessage());
            }
        }
    }
    
    /**
     * 执行异常拦截器
     */
    public void executeAfterThrowing(RequestContext context, Exception ex) {
        for (RequestInterceptor interceptor : interceptors) {
            try {
                interceptor.afterThrowing(context, ex);
            } catch (Exception e) {
                // 记录日志但不中断其他拦截器的执行
                System.err.println("AfterThrowing interceptor failed: " + e.getMessage());
            }
        }
    }
}

在 HttpClientInvocationHandler 中集成

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    // 创建请求上下文
    DefaultRequestContext context = createRequestContext(method, args);
    
    // 构建拦截器链
    List<RequestInterceptor> allInterceptors = buildInterceptorChain(method);
    InterceptorChain interceptorChain = new InterceptorChain(allInterceptors);
    
    try {
        // 执行前置拦截器
        interceptorChain.executePreHandle(context);
        
        // 如果拦截器已经设置了响应,直接返回
        if (context.getResponse() != null) {
            return handleResponse(context, method);
        }
        
        // 构建并执行HTTP请求
        HttpRequest request = buildHttpRequest(method, args);
        context.setRequest(request);
        
        Object result = executeHttpRequest(context, method);
        
        // 执行后置拦截器
        interceptorChain.executePostHandle(context);
        
        return result;
        
    } catch (Exception e) {
        // 执行异常拦截器
        interceptorChain.executeAfterThrowing(context, e);
        throw e;
    }
}

/**
 * 构建拦截器链
 */
private List<RequestInterceptor> buildInterceptorChain(Method method) {
    List<RequestInterceptor> chain = new ArrayList<>();
    
    // 1. 添加全局拦截器
    chain.addAll(HttpClientFactory.getGlobalInterceptors());
    
    // 2. 添加类级别拦截器
    Class<?> clientClass = method.getDeclaringClass();
    if (clientClass.isAnnotationPresent(Interceptor.class)) {
        Interceptor interceptorAnnotation = clientClass.getAnnotation(Interceptor.class);
        for (Class<? extends RequestInterceptor> interceptorClass : interceptorAnnotation.value()) {
            try {
                chain.add(interceptorClass.newInstance());
            } catch (Exception e) {
                throw new RuntimeException("Failed to create interceptor: " + interceptorClass.getName(), e);
            }
        }
    }
    
    // 3. 添加方法级别拦截器
    if (method.isAnnotationPresent(MethodInterceptor.class)) {
        MethodInterceptor methodInterceptor = method.getAnnotation(MethodInterceptor.class);
        for (Class<? extends RequestInterceptor> interceptorClass : methodInterceptor.value()) {
            try {
                chain.add(interceptorClass.newInstance());
            } catch (Exception e) {
                throw new RuntimeException("Failed to create method interceptor: " + interceptorClass.getName(), e);
            }
        }
    }
    
    return chain;
}

使用示例

1. 基本使用

// 配置全局拦截器
HttpClientFactory.addGlobalInterceptor(new LoggingInterceptor());
HttpClientFactory.addGlobalInterceptor(new MetricsInterceptor());

// 定义接口
@HttpClient("https://api.example.com")
@Interceptor({AuthInterceptor.class})
public interface UserService {
    @GET("/users")
    List<User> getUsers();
    
    @POST("/users")
    @MethodInterceptor({RetryInterceptor.class})
    User createUser(@Body User user);
}

// 使用
UserService userService = HttpClientFactory.create(UserService.class);
List<User> users = userService.getUsers();

2. 自定义拦截器

/**
 * 自定义缓存拦截器
 */
public class CacheInterceptor extends AbstractRequestInterceptor {
    private final Map<String, CacheEntry> cache = new ConcurrentHashMap<>();
    private final long ttl;
    
    public CacheInterceptor(long ttl) {
        this.ttl = ttl;
    }
    
    @Override
    public void preHandle(RequestContext context) throws Exception {
        Request request = context.getRequest();
        
        // 只缓存GET请求
        if (request.getMethod() != HttpMethod.GET) {
            return;
        }
        
        String cacheKey = request.getUrl();
        CacheEntry entry = cache.get(cacheKey);
        
        if (entry != null && !entry.isExpired()) {
            // 缓存命中,设置响应
            context.setResponse(entry.response);
        }
    }
    
    @Override
    public void postHandle(RequestContext context) throws Exception {
        Request request = context.getRequest();
        Response response = context.getResponse();
        
        // 只缓存成功的GET请求
        if (request.getMethod() == HttpMethod.GET && 
            response.getStatusCode() >= 200 && response.getStatusCode() < 300) {
            
            String cacheKey = request.getUrl();
            cache.put(cacheKey, new CacheEntry(response, System.currentTimeMillis() + ttl));
        }
    }
    
    private static class CacheEntry {
        final Response response;
        final long expireTime;
        
        CacheEntry(Response response, long expireTime) {
            this.response = response;
            this.expireTime = expireTime;
        }
        
        boolean isExpired() {
            return System.currentTimeMillis() > expireTime;
        }
    }
}

3. 条件拦截器

/**
 * 条件拦截器
 * 只在满足特定条件时执行
 */
public class ConditionalInterceptor extends AbstractRequestInterceptor {
    private final Predicate<RequestContext> condition;
    private final RequestInterceptor delegate;
    
    public ConditionalInterceptor(Predicate<RequestContext> condition, RequestInterceptor delegate) {
        this.condition = condition;
        this.delegate = delegate;
    }
    
    @Override
    public void preHandle(RequestContext context) throws Exception {
        if (condition.test(context)) {
            delegate.preHandle(context);
        }
    }
    
    @Override
    public void postHandle(RequestContext context) throws Exception {
        if (condition.test(context)) {
            delegate.postHandle(context);
        }
    }
    
    @Override
    public void afterThrowing(RequestContext context, Exception ex) throws Exception {
        if (condition.test(context)) {
            delegate.afterThrowing(context, ex);
        }
    }
}

// 使用示例
RequestInterceptor conditionalLogger = new ConditionalInterceptor(
    context -> context.getRequest().getUrl().contains("/api/v1/"),
    new LoggingInterceptor()
);

HttpClientFactory.addGlobalInterceptor(conditionalLogger);

最佳实践

1. 拦截器设计原则

  • 单一职责:每个拦截器只负责一个特定的功能
  • 无状态设计:拦截器应该是无状态的,避免并发问题
  • 异常安全:拦截器中的异常不应该影响其他拦截器的执行
  • 性能考虑:避免在拦截器中执行耗时操作

2. 拦截器顺序

合理安排拦截器的执行顺序:

// 推荐的拦截器顺序
HttpClientFactory.addGlobalInterceptor(new MetricsInterceptor());     // 1. 性能监控
HttpClientFactory.addGlobalInterceptor(new LoggingInterceptor());     // 2. 日志记录
HttpClientFactory.addGlobalInterceptor(new AuthInterceptor(token));   // 3. 认证处理
HttpClientFactory.addGlobalInterceptor(new RetryInterceptor());       // 4. 重试逻辑

3. 错误处理

public class SafeInterceptorChain {
    public void executePreHandle(RequestContext context) throws Exception {
        Exception firstException = null;
        
        for (RequestInterceptor interceptor : interceptors) {
            try {
                interceptor.preHandle(context);
            } catch (Exception e) {
                if (firstException == null) {
                    firstException = e;
                }
                // 记录日志但继续执行其他拦截器
                logger.error("Interceptor preHandle failed: " + interceptor.getClass().getName(), e);
            }
        }
        
        // 如果有异常,抛出第一个异常
        if (firstException != null) {
            throw firstException;
        }
    }
}

总结

本文详细介绍了 Atlas HTTP Client 框架的拦截器机制设计与实现。关键要点包括:

  1. 核心接口:简洁的 RequestInterceptor 接口设计
  2. 内置拦截器:日志、认证、重试、性能监控等常用拦截器
  3. 配置机制:支持全局、类级别和方法级别的灵活配置
  4. 执行机制:责任链模式的拦截器链执行
  5. 扩展性:易于实现自定义拦截器
  6. 最佳实践:设计原则和使用建议
本站提供的所有下载资源均来自互联网,仅提供学习交流使用,版权归原作者所有。如需商业使用,请联系原作者获得授权。 如您发现有涉嫌侵权的内容,请联系我们 邮箱:[email protected]