# 网络请求优化

## 目录
- [请求合并](#请求合并)
- [请求去重](#请求去重)
- [请求重试](#请求重试)
- [请求缓存](#请求缓存)
- [请求优先级](#请求优先级)
- [网络监控](#网络监控)
- [网络请求优化最佳实践](#网络请求优化最佳实践)
- [面试常见问题](#面试常见问题)

---

## 请求合并

### 批量请求

```java
// ❌ 问题：频繁请求
for (int i = 0; i < 100; i++) {
    api.getUserInfo(i).enqueue(callback);
}

// ✅ 解决：批量请求
List<Integer> userIds = new ArrayList<>();
for (int i = 0; i < 100; i++) {
    userIds.add(i);
}
api.getBatchUserInfo(userIds).enqueue(callback);
```

### 请求合并器

```java
public class RequestMerger {
    private Handler handler = new Handler(Looper.getMainLooper());
    private List<Request> pendingRequests = new ArrayList<>();
    private Runnable mergeRunnable = new Runnable() {
        @Override
        public void run() {
            if (!pendingRequests.isEmpty()) {
                executeBatch(pendingRequests);
                pendingRequests.clear();
            }
        }
    };
    
    public void addRequest(Request request) {
        pendingRequests.add(request);
        handler.removeCallbacks(mergeRunnable);
        handler.postDelayed(mergeRunnable, 100); // 100ms 内合并
    }
}
```

---

## 请求去重

### 去重实现

```java
public class RequestDeduplicator {
    private Map<String, Call> pendingRequests = new ConcurrentHashMap<>();
    
    public <T> void execute(String key, Call<T> call, Callback<T> callback) {
        Call<T> existingCall = (Call<T>) pendingRequests.get(key);
        if (existingCall != null) {
            call.cancel();
            return;
        }
        
        pendingRequests.put(key, call);
        call.enqueue(new Callback<T>() {
            @Override
            public void onResponse(Call<T> call, Response<T> response) {
                pendingRequests.remove(key);
                callback.onResponse(call, response);
            }
            
            @Override
            public void onFailure(Call<T> call, Throwable t) {
                pendingRequests.remove(key);
                callback.onFailure(call, t);
            }
        });
    }
}
```

---

## 请求重试

### 重试实现

```java
public class RetryInterceptor implements Interceptor {
    private int maxRetries;
    
    public RetryInterceptor(int maxRetries) {
        this.maxRetries = maxRetries;
    }
    
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();
        Response response = null;
        IOException exception = null;
        
        for (int i = 0; i <= maxRetries; i++) {
            try {
                response = chain.proceed(request);
                if (response.isSuccessful()) {
                    return response;
                }
            } catch (IOException e) {
                exception = e;
                if (i == maxRetries) {
                    throw e;
                }
            }
            
            // 等待后重试
            try {
                Thread.sleep(1000 * (i + 1));
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
        
        throw exception;
    }
}
```

---

## 请求缓存

### 三级缓存

```java
public class CacheManager {
    private LruCache<String, Response> memoryCache;
    private DiskCache diskCache;
    
    public Response get(String url) {
        // 1. 检查内存缓存
        Response response = memoryCache.get(url);
        if (response != null) {
            return response;
        }
        
        // 2. 检查磁盘缓存
        response = diskCache.get(url);
        if (response != null) {
            memoryCache.put(url, response);
            return response;
        }
        
        // 3. 从网络加载
        return null;
    }
}
```

---

## 请求优先级

### 优先级实现

```java
public class PriorityInterceptor implements Interceptor {
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();
        int priority = request.header("Priority") != null 
            ? Integer.parseInt(request.header("Priority")) 
            : 0;
        
        // 根据优先级处理
        return chain.proceed(request);
    }
}

// 使用
Request request = new Request.Builder()
    .url("https://api.example.com/data")
    .addHeader("Priority", "10")
    .build();
```

---

## 网络监控

### 监控实现

```java
public class NetworkMonitorInterceptor implements Interceptor {
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();
        long startTime = System.currentTimeMillis();
        
        Response response = chain.proceed(request);
        
        long endTime = System.currentTimeMillis();
        long duration = endTime - startTime;
        
        // 记录请求信息
        Log.d("Network", String.format(
            "Request: %s, Duration: %dms, Size: %d bytes",
            request.url(), duration,
            response.body() != null ? response.body().contentLength() : 0
        ));
        
        return response;
    }
}
```

---

## 网络请求优化最佳实践

### 1. 合并请求

```java
// 将多个请求合并为一个批量请求
```

### 2. 使用缓存

```java
// 使用三级缓存减少网络请求
```

### 3. 设置超时

```java
// 合理设置超时时间
OkHttpClient client = new OkHttpClient.Builder()
    .connectTimeout(10, TimeUnit.SECONDS)
    .readTimeout(30, TimeUnit.SECONDS)
    .build();
```

---

## 面试常见问题

### Q1: 如何优化网络请求？

**答案：**
1. 请求合并：批量请求
2. 请求去重：避免重复请求
3. 请求缓存：三级缓存
4. 请求重试：失败自动重试

### Q2: 请求合并的实现？

**答案：**
- 将多个请求合并为一个批量请求
- 使用请求合并器延迟执行
- 减少网络请求次数

### Q3: 请求去重的作用？

**答案：**
- 避免重复请求相同数据
- 减少网络请求
- 提升性能

---

*最后更新：2024年*
