feat: 实现用户认证系统并优化音频播放器功能

- 新增NextAuth认证系统,支持Google和GitHub登录
- 添加登录模态框组件和用户头像显示
- 重构音频播放器,支持倍速控制和状态同步
- 优化播客卡片显示当前播放状态和生成状态
- 新增API调用追踪工具和防重复调用Hook
- 修复多个API重复调用问题并添加详细文档
- 改进音频文件处理流程,支持MP3格式输出
- 更新类型定义和组件Props以支持新功能
This commit is contained in:
hex2077
2025-08-16 23:03:46 +08:00
parent 719eb14927
commit b63fcb3f6d
32 changed files with 1585 additions and 989 deletions

View 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调用追踪器新增
## 注意事项
- 修复后的代码保持了原有功能不变
- 所有修改都向后兼容
- 调试工具只在开发环境中启用,不会影响生产环境性能
- 建议在部署前进行充分测试,确保所有功能正常工作