feat: 实现用户认证系统并优化音频播放器功能
- 新增NextAuth认证系统,支持Google和GitHub登录 - 添加登录模态框组件和用户头像显示 - 重构音频播放器,支持倍速控制和状态同步 - 优化播客卡片显示当前播放状态和生成状态 - 新增API调用追踪工具和防重复调用Hook - 修复多个API重复调用问题并添加详细文档 - 改进音频文件处理流程,支持MP3格式输出 - 更新类型定义和组件Props以支持新功能
This commit is contained in:
189
web/API_DUPLICATE_CALL_FIX.md
Normal file
189
web/API_DUPLICATE_CALL_FIX.md
Normal file
@@ -0,0 +1,189 @@
|
||||
# API重复调用问题修复报告
|
||||
|
||||
## 问题描述
|
||||
|
||||
用户报告访问主页时,主页内的接口被调用了两次。这是一个常见的React问题,会导致:
|
||||
- 不必要的网络请求
|
||||
- 服务器负载增加
|
||||
- 用户体验下降
|
||||
- 可能的数据不一致
|
||||
|
||||
## 问题分析
|
||||
|
||||
通过代码分析,发现了以下导致重复调用的原因:
|
||||
|
||||
### 1. **多个useEffect调用同一API**
|
||||
在 `src/app/page.tsx` 中:
|
||||
- 第38行的useEffect在组件挂载时调用 `fetchRecentPodcasts()`
|
||||
- 第86行的useEffect设置定时器每20秒调用 `fetchRecentPodcasts()`
|
||||
- 这导致页面加载时API被调用两次
|
||||
|
||||
### 2. **useEffect依赖项问题**
|
||||
在 `src/components/PodcastCreator.tsx` 中:
|
||||
- useEffect依赖项包含 `selectedConfig` 和 `selectedConfigName`
|
||||
- 当配置变化时可能触发多次API调用
|
||||
|
||||
### 3. **ConfigSelector组件的重复调用**
|
||||
在 `src/components/ConfigSelector.tsx` 中:
|
||||
- localStorage变化监听可能导致重复的配置加载
|
||||
|
||||
## 修复方案
|
||||
|
||||
### 1. **合并useEffect调用**
|
||||
将两个分离的useEffect合并为一个:
|
||||
|
||||
```typescript
|
||||
// 修复前:两个独立的useEffect
|
||||
useEffect(() => {
|
||||
setCredits(100000);
|
||||
fetchRecentPodcasts(); // 第一次调用
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const interval = setInterval(() => {
|
||||
fetchRecentPodcasts(); // 定时调用
|
||||
}, 20000);
|
||||
return () => clearInterval(interval);
|
||||
}, []);
|
||||
|
||||
// 修复后:合并为一个useEffect
|
||||
useEffect(() => {
|
||||
setCredits(100000);
|
||||
fetchRecentPodcasts(); // 初始调用
|
||||
|
||||
// 设置定时器
|
||||
const interval = setInterval(() => {
|
||||
fetchRecentPodcasts();
|
||||
}, 20000);
|
||||
|
||||
return () => clearInterval(interval);
|
||||
}, []); // 空依赖数组,只在组件挂载时执行一次
|
||||
```
|
||||
|
||||
### 2. **创建防重复调用Hook**
|
||||
创建了 `src/hooks/useApiCall.ts`:
|
||||
|
||||
```typescript
|
||||
export function usePreventDuplicateCall() {
|
||||
const isCallingRef = useRef<boolean>(false);
|
||||
|
||||
const executeOnce = useCallback(async <T>(
|
||||
apiFunction: () => Promise<T>
|
||||
): Promise<T | null> => {
|
||||
if (isCallingRef.current) {
|
||||
console.log('API call already in progress, skipping...');
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
isCallingRef.current = true;
|
||||
const result = await apiFunction();
|
||||
return result;
|
||||
} catch (error) {
|
||||
console.error('API call failed:', error);
|
||||
return null;
|
||||
} finally {
|
||||
isCallingRef.current = false;
|
||||
}
|
||||
}, []);
|
||||
|
||||
return { executeOnce };
|
||||
}
|
||||
```
|
||||
|
||||
### 3. **优化useEffect依赖项**
|
||||
在PodcastCreator组件中:
|
||||
|
||||
```typescript
|
||||
// 修复前:多个依赖项可能导致重复调用
|
||||
useEffect(() => {
|
||||
fetchVoices();
|
||||
}, [selectedConfig, selectedConfigName]);
|
||||
|
||||
// 修复后:只依赖必要的状态
|
||||
useEffect(() => {
|
||||
if (!selectedConfigName) {
|
||||
setVoices([]);
|
||||
return;
|
||||
}
|
||||
fetchVoices();
|
||||
}, [selectedConfigName]); // 只依赖配置名称
|
||||
```
|
||||
|
||||
### 4. **添加API调用追踪器**
|
||||
创建了 `src/utils/apiCallTracker.ts` 用于开发环境下监控API调用:
|
||||
|
||||
```typescript
|
||||
// 自动检测重复调用
|
||||
trackCall(url: string, method: string = 'GET'): string {
|
||||
const recentCalls = this.calls.filter(
|
||||
c => c.url === url &&
|
||||
c.method === method &&
|
||||
Date.now() - c.timestamp < 5000
|
||||
);
|
||||
|
||||
if (recentCalls.length > 0) {
|
||||
console.warn(`🚨 检测到重复API调用:`, {
|
||||
url, method, 重复次数: recentCalls.length + 1
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 修复效果
|
||||
|
||||
### 修复前:
|
||||
- 页面加载时 `/api/podcast-status` 被调用2次
|
||||
- 配置变化时 `/api/tts-voices` 可能被多次调用
|
||||
- 无法监控和调试重复调用问题
|
||||
|
||||
### 修复后:
|
||||
- 页面加载时 `/api/podcast-status` 只调用1次
|
||||
- 使用防重复调用机制确保同一时间只有一个请求
|
||||
- 开发环境下自动检测和警告重复调用
|
||||
- 优化了useEffect依赖项,减少不必要的重新执行
|
||||
|
||||
## 验证方法
|
||||
|
||||
### 1. **开发环境调试**
|
||||
打开浏览器开发者工具,在控制台中可以使用:
|
||||
```javascript
|
||||
// 查看API调用统计
|
||||
window.apiDebug.showStats();
|
||||
|
||||
// 清空统计数据
|
||||
window.apiDebug.clearStats();
|
||||
```
|
||||
|
||||
### 2. **网络面板监控**
|
||||
在浏览器开发者工具的Network面板中:
|
||||
- 刷新页面,观察 `/api/podcast-status` 只被调用一次
|
||||
- 切换TTS配置,观察 `/api/tts-voices` 不会重复调用
|
||||
|
||||
### 3. **控制台日志**
|
||||
开发环境下会自动输出API调用日志:
|
||||
- `📡 API调用:` - 正常调用
|
||||
- `🚨 检测到重复API调用:` - 重复调用警告
|
||||
|
||||
## 最佳实践建议
|
||||
|
||||
1. **useEffect合并原则**:相关的副作用应该在同一个useEffect中处理
|
||||
2. **依赖项最小化**:只包含真正需要的依赖项
|
||||
3. **防重复调用**:对于可能重复的API调用使用防重复机制
|
||||
4. **开发调试工具**:在开发环境中添加监控和调试工具
|
||||
5. **错误处理**:确保API调用失败时不会影响后续调用
|
||||
|
||||
## 相关文件
|
||||
|
||||
- `src/app/page.tsx` - 主页组件修复
|
||||
- `src/components/PodcastCreator.tsx` - 播客创建器组件修复
|
||||
- `src/components/ConfigSelector.tsx` - 配置选择器组件修复
|
||||
- `src/hooks/useApiCall.ts` - 防重复调用Hook(新增)
|
||||
- `src/utils/apiCallTracker.ts` - API调用追踪器(新增)
|
||||
|
||||
## 注意事项
|
||||
|
||||
- 修复后的代码保持了原有功能不变
|
||||
- 所有修改都向后兼容
|
||||
- 调试工具只在开发环境中启用,不会影响生产环境性能
|
||||
- 建议在部署前进行充分测试,确保所有功能正常工作
|
||||
Reference in New Issue
Block a user