feat: 实现用户认证系统并优化音频播放器功能
- 新增NextAuth认证系统,支持Google和GitHub登录 - 添加登录模态框组件和用户头像显示 - 重构音频播放器,支持倍速控制和状态同步 - 优化播客卡片显示当前播放状态和生成状态 - 新增API调用追踪工具和防重复调用Hook - 修复多个API重复调用问题并添加详细文档 - 改进音频文件处理流程,支持MP3格式输出 - 更新类型定义和组件Props以支持新功能
This commit is contained in:
96
web/src/utils/apiCallTracker.ts
Normal file
96
web/src/utils/apiCallTracker.ts
Normal file
@@ -0,0 +1,96 @@
|
||||
/**
|
||||
* API调用追踪器 - 用于调试和监控API调用
|
||||
* 在开发环境中帮助识别重复调用问题
|
||||
*/
|
||||
|
||||
interface ApiCall {
|
||||
url: string;
|
||||
method: string;
|
||||
timestamp: number;
|
||||
id: string;
|
||||
}
|
||||
|
||||
class ApiCallTracker {
|
||||
private calls: ApiCall[] = [];
|
||||
private isDevelopment = process.env.NODE_ENV === 'development';
|
||||
|
||||
// 记录API调用
|
||||
trackCall(url: string, method: string = 'GET'): string {
|
||||
if (!this.isDevelopment) return '';
|
||||
|
||||
const id = `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
||||
const call: ApiCall = {
|
||||
url,
|
||||
method,
|
||||
timestamp: Date.now(),
|
||||
id
|
||||
};
|
||||
|
||||
this.calls.push(call);
|
||||
|
||||
// 检查是否有重复调用(5秒内相同URL和方法)
|
||||
const recentCalls = this.calls.filter(
|
||||
c => c.url === url &&
|
||||
c.method === method &&
|
||||
Date.now() - c.timestamp < 5000 &&
|
||||
c.id !== id
|
||||
);
|
||||
|
||||
if (recentCalls.length > 0) {
|
||||
console.warn(`🚨 检测到重复API调用:`, {
|
||||
url,
|
||||
method,
|
||||
重复次数: recentCalls.length + 1,
|
||||
最近调用时间: recentCalls.map(c => new Date(c.timestamp).toLocaleTimeString())
|
||||
});
|
||||
} else {
|
||||
console.log(`📡 API调用:`, { url, method, time: new Date().toLocaleTimeString() });
|
||||
}
|
||||
|
||||
// 清理超过1分钟的记录
|
||||
this.calls = this.calls.filter(c => Date.now() - c.timestamp < 60000);
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
// 获取调用统计
|
||||
getStats(): { [key: string]: number } {
|
||||
const stats: { [key: string]: number } = {};
|
||||
this.calls.forEach(call => {
|
||||
const key = `${call.method} ${call.url}`;
|
||||
stats[key] = (stats[key] || 0) + 1;
|
||||
});
|
||||
return stats;
|
||||
}
|
||||
|
||||
// 清空记录
|
||||
clear(): void {
|
||||
this.calls = [];
|
||||
}
|
||||
}
|
||||
|
||||
// 创建全局实例
|
||||
export const apiCallTracker = new ApiCallTracker();
|
||||
|
||||
// 包装fetch函数以自动追踪
|
||||
export const trackedFetch = (url: string, options?: RequestInit) => {
|
||||
const method = options?.method || 'GET';
|
||||
apiCallTracker.trackCall(url, method);
|
||||
return fetch(url, options);
|
||||
};
|
||||
|
||||
// 开发环境下的调试工具
|
||||
export const showApiStats = () => {
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
console.table(apiCallTracker.getStats());
|
||||
}
|
||||
};
|
||||
|
||||
// 在控制台暴露调试工具
|
||||
if (typeof window !== 'undefined' && process.env.NODE_ENV === 'development') {
|
||||
(window as any).apiDebug = {
|
||||
showStats: showApiStats,
|
||||
clearStats: () => apiCallTracker.clear(),
|
||||
tracker: apiCallTracker
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user