故障排查
本文提供 Lovrabet SDK 常见问题的解决方案,帮助您快速诊断和修复问题。
🔧 常见问题诊断
问题诊断流程
在遇到问题时,请按以下步骤进行排查:
- 检查错误信息 - 查看控制台错误日志
- 验证配置 - 确认 SDK 配置正确
- 检查网络 - 查看网络请求状态
- 验证权限 - 确认 API 访问权限
- 查看文档 - 对照本文档检查用法
启用详细日志
// 启用详细的错误日志
const client = createClient({
options: {
onError: (error) => {
console.group("🔍 Lovrabet SDK Error Details");
console.log("📝 Message:", error.message);
console.log("🔢 Status:", error.status);
console.log("🌐 URL:", error.url);
console.log("📤 Request Data:", error.requestData);
console.log("📥 Response Data:", error.responseData);
console.log("⏱️ Timestamp:", new Date().toISOString());
console.log("🔗 Stack:", error.stack);
console.groupEnd();
},
},
});
❌ 配置相关问题
Q1: "Cannot find module '@lovrabet/sdk'"
问题描述:项目无法找到 SDK 模块
解决方案:
# 确认 SDK 已安装
npm list @lovrabet/sdk
# 如果未安装,请安装
npm install @lovrabet/sdk
# 如果是 TypeScript 项目,确认类型支持
npm install --save-dev typescript
Q2: "registerModels is not a function"
问题描述:导入函数出现问题
解决方案:
// ❌ 错误的导入方式
import lovrabetSdk from "@lovrabet/sdk";
lovrabetSdk.registerModels(config); // 会报错
// ✅ 正确的导入方式
import { registerModels, createClient } from "@lovrabet/sdk";
registerModels(config);
Q3: "No configuration found for apiConfigName 'default'"
问题描述:找不到默认配置
解决方案:
// ❌ 问题:没有注册配置就直接使用
const client = createClient(); // 会报错
// ✅ 解决:先注册配置
registerModels({
appCode: "your-app-code",
models: {
users: { tableName: "users", datasetCode: "your-dataset-id" },
},
});
const client = createClient(); // 正常工作
Q4: AppCode 配置问题
问题描述:appCode 配置错误或缺失
解决方案:
// 检查环境变量
console.log("AppCode:", process.env.REACT_APP_LOVRABET_APP_CODE);
// 确保配置正确
const config = {
appCode: "your-actual-app-code", // 不要使用 "your-app-code"
models: {
// ...
},
};
// 验证配置
if (!config.appCode) {
throw new Error("AppCode is required");
}
🔐 认证相关问题
Q5: "Authentication failed" / 401 错误
问题描述:认证失败,无法访问 API
解决方案:
// 1. 检查 token 是否设置
const client = createClient();
console.log("Current token:", client.getConfig().token);
// 2. 设置 token
client.setToken("your-valid-token");
// 3. 检查 token 格式
if (token && !token.startsWith("Bearer ")) {
client.setToken(`Bearer ${token}`);
}
// 4. 检查 token 是否过期
const isTokenExpired = (token: string) => {
try {
const payload = JSON.parse(atob(token.split(".")[1]));
return payload.exp * 1000 < Date.now();
} catch {
return true;
}
};
Q6: OpenAPI 密钥认证问题
问题描述:使用 OpenAPI 密钥时认证失败
解决方案:
// 检查密钥配置
const client = createClient({
accessKey: process.env.LOVRABET_ACCESS_KEY,
secretKey: process.env.LOVRABET_SECRET_KEY,
});
// 验证密钥存在
const config = client.getConfig();
console.log("Has Access Key:", !!config.accessKey);
console.log("Has Secret Key:", !!config.secretKey);
// 确保环境变量正确设置
if (!process.env.LOVRABET_ACCESS_KEY) {
console.error("Missing LOVRABET_ACCESS_KEY environment variable");
}
Q7: Cookie 认证问题
问题描述:在浏览器中 Cookie 认证失败
解决方案:
// 检查 Cookie 设置
document.cookie.split(";").forEach((cookie) => {
console.log("Cookie:", cookie.trim());
});
// 确保域名和路径设置正确
// 检查是否在同源域下
console.log("Current origin:", window.location.origin);
console.log("API endpoint:", client.getConfig().serverUrl);
🌐 网络相关问题
Q8: "Network Error" / 连接失败
问题描述:网络请求失败
解决方案:
// 1. 检查服务器地址
const client = createClient({
serverUrl: "https://api.lovrabet.com", // 确保地址正确
});
// 2. 检查网络连接
const testConnection = async () => {
try {
const response = await fetch("https://api.lovrabet.com/health");
console.log("API健康检查:", response.status);
} catch (error) {
console.error("网络连接问题:", error);
}
};
// 3. 检查 CORS 设置(前端)
// 确保服务器配置了正确的 CORS 头
Q9: 请求超时问题
问题描述:请求经常超时
解决方案:
// 增加超时时间
const client = createClient({
options: {
timeout: 60000, // 60秒
},
});
// 实现请求重试
const withRetry = async <T>(
operation: () => Promise<T>,
maxRetries = 3
): Promise<T> => {
let lastError: any;
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
return await operation();
} catch (error: any) {
lastError = error;
if (error.code === "TIMEOUT" && attempt < maxRetries) {
console.log(`请求超时,重试 ${attempt}/${maxRetries}`);
await new Promise((resolve) => setTimeout(resolve, 1000 * attempt));
continue;
}
throw error;
}
}
throw lastError;
};
Q10: 速率限制问题
问题描述:收到 429 Too Many Requests 错误
解决方案:
// 实现请求限流
class RateLimiter {
private requests: number[] = [];
private maxRequests: number;
private timeWindow: number;
constructor(maxRequests = 100, timeWindowMs = 60000) {
this.maxRequests = maxRequests;
this.timeWindow = timeWindowMs;
}
async waitForAvailability(): Promise<void> {
const now = Date.now();
// 清理过期的请求记录
this.requests = this.requests.filter(
(time) => now - time < this.timeWindow
);
if (this.requests.length >= this.maxRequests) {
const oldestRequest = Math.min(...this.requests);
const waitTime = this.timeWindow - (now - oldestRequest);
console.log(`Rate limit reached, waiting ${waitTime}ms`);
await new Promise((resolve) => setTimeout(resolve, waitTime));
return this.waitForAvailability();
}
this.requests.push(now);
}
}
const rateLimiter = new RateLimiter();
const makeRequest = async (operation: () => Promise<any>) => {
await rateLimiter.waitForAvailability();
return operation();
};
📊 数据相关问题
Q11: "Dataset not found" 错误
问题描述:数据集不存在或无权访问
解决方案:
// 验证数据集ID
const verifyDataset = async (datasetCode: string) => {
try {
// 尝试获取数据集信息
const response = await client.models.yourModel.filter({ pageSize: 1 });
console.log("数据集验证成功:", response.total);
} catch (error: any) {
if (error.status === 404) {
console.error("数据集不存在:", datasetCode);
} else if (error.status === 403) {
console.error("没有访问权限:", datasetCode);
}
throw error;
}
};
// 检查配置中的数据集ID
console.log("配置的数据集ID:", client.getConfig().models);
Q12: 数据格式问题
问题描述:返回的数据格式不符合预期
解决方案:
// 添加数据验证
const validateResponseData = (data: any, expectedFields: string[]) => {
if (!data || typeof data !== "object") {
throw new Error("Invalid response data format");
}
const missingFields = expectedFields.filter((field) => !(field in data));
if (missingFields.length > 0) {
console.warn("Missing fields:", missingFields);
}
return data;
};
// 使用时验证数据
const users = await client.models.users.filter();
users.tableData.forEach((user) => {
validateResponseData(user, ["id", "name", "email"]);
});
Q13: 分页数据问题
问题描述:分页参数不正确或分页数据异常
解决方案:
// 验证分页参数
const validatePaginationParams = (params: any) => {
const { currentPage, pageSize } = params;
if (currentPage && (currentPage < 1 || !Number.isInteger(currentPage))) {
throw new Error("currentPage must be a positive integer");
}
if (
pageSize &&
(pageSize < 1 || pageSize > 1000 || !Number.isInteger(pageSize))
) {
throw new Error("pageSize must be between 1 and 1000");
}
return params;
};
// 安全的分页查询
const safeGetList = async (modelName: string, params: any = {}) => {
const validatedParams = validatePaginationParams(params);
return await client.models[modelName].filter(validatedParams);
};
🔍 调试工具和技巧
调试助手类
class LovrabetDebugger {
private client: any;
constructor(client: any) {
this.client = client;
}
// 测试连接
async testConnection(): Promise<boolean> {
try {
// 尝试获取少量数据测试连接
await this.client.models[Object.keys(this.client.getConfig().models)[0]].filter({ pageSize: 1 });
console.log("✅ 连接测试成功");
return true;
} catch (error: any) {
console.error("❌ 连接测试失败:", error.message);
return false;
}
}
// 检查配置
checkConfiguration(): void {
const config = this.client.getConfig();
console.group("🔧 配置检查");
console.log("AppCode:", config.appCode);
console.log("Environment:", config.env);
console.log("Server URL:", config.serverUrl);
console.log("Has Token:", !!config.token);
console.log("Has Access Key:", !!config.accessKey);
console.log("Models:", Object.keys(config.models || {}));
console.groupEnd();
}
// 测试所有模型
async testAllModels(): Promise<void> {
const config = this.client.getConfig();
const modelNames = Object.keys(config.models || {});
console.log("🧪 测试所有模型...");
for (const modelName of modelNames) {
try {
const response = await this.client.models[modelName].filter({ pageSize: 1 });
console.log(`✅ ${modelName}: ${response.total} records`);
} catch (error: any) {
console.error(`❌ ${modelName}: ${error.message}`);
}
}
}
// 性能测试
async performanceTest(modelName: string, iterations = 10): Promise<void> {
console.log(`⚡ 性能测试 ${modelName} (${iterations} 次请求)`);
const times: number[] = [];
for (let i = 0; i < iterations; i++) {
const start = Date.now();
try {
await this.client.models[modelName].filter({ pageSize: 10 });
const duration = Date.now() - start;
times.push(duration);
console.log(`请求 ${i + 1}: ${duration}ms`);
} catch (error: any) {
console.error(`请求 ${i + 1} 失败:`, error.message);
}
}
if (times.length > 0) {
const avg = times.reduce((a, b) => a + b, 0) / times.length;
const min = Math.min(...times);
const max = Math.max(...times);
console.log(`📊 性能统计:`);
console.log(`平均耗时: ${avg.toFixed(2)}ms`);
console.log(`最短耗时: ${min}ms`);
console.log(`最长耗时: ${max}ms`);
}
}
// 检查权限
async checkPermissions(modelName: string): Promise<void> {
console.log(`🔒 检查 ${modelName} 权限`);
const tests = [
{ name: "读取", action: () => this.client.models[modelName].filter({ pageSize: 1 }) },
{ name: "创建", action: () => this.client.models[modelName].create({ test: true }) },
{ name: "更新", action: () => this.client.models[modelName].update("test-id", { test: true }) },
{ name: "删除", action: () => this.client.models[modelName].delete("test-id") },
];
for (const test of tests) {
try {
await test.action();
console.log(`✅ ${test.name}: 有权限`);
} catch (error: any) {
if (error.status === 403) {
console.log(`❌ ${test.name}: 无权限`);
} else if (error.status === 404) {
console.log(`⚠️ ${test.name}: 资源不存在(可能有权限)`);
} else {
console.log(`❌ ${test.name}: ${error.message}`);
}
}
}
}
}
// 使用调试器
const debugger = new LovrabetDebugger(client);
// 运行完整诊断
const runDiagnostics = async () => {
debugger.checkConfiguration();
await debugger.testConnection();
await debugger.testAllModels();
await debugger.checkPermissions("users");
await debugger.performanceTest("users", 5);
};
浏览器开发者工具
// 在浏览器控制台中添加调试方法
(window as any).lovrabetDebug = {
client,
// 快速测试
async test() {
const debugger = new LovrabetDebugger(client);
await debugger.testConnection();
},
// 查看配置
config() {
console.table(client.getConfig());
},
// 查看最近的请求
requests: [],
// 添加请求监听
enableRequestLogging() {
const originalFetch = window.fetch;
(window as any).lovrabetDebug.requests = [];
window.fetch = function(...args) {
const start = Date.now();
const url = typeof args[0] === 'string' ? args[0] : args[0].url;
return originalFetch.apply(this, args).then(response => {
(window as any).lovrabetDebug.requests.push({
url,
status: response.status,
duration: Date.now() - start,
timestamp: new Date().toISOString(),
});
return response;
});
};
console.log("✅ 请求日志已启用,使用 lovrabetDebug.requests 查看");
},
};
console.log("🔧 调试工具已加载,使用 lovrabetDebug 访问");
📞 获取帮助
自助排查清单
在联系技术支持前,请完成以下检查:
- 确认 SDK 版本是最新的
- 检查控制台是否有错误信息
- 验证 appCode 和 datasetCode 配置正确
- 测试网络连接是否正常
- 确认 API 认证配置正确
- 尝试简单的测试请求
提供问题信息
当需要技术支持时,请提供以下信息:
// 收集问题信息的工具函数
const collectProblemInfo = () => {
const info = {
sdkVersion: "1.0.0", // 检查 package.json
browser: navigator.userAgent,
timestamp: new Date().toISOString(),
config: {
appCode: client.getConfig().appCode,
env: client.getConfig().env,
hasToken: !!client.getConfig().token,
hasAccessKey: !!client.getConfig().accessKey,
modelsCount: Object.keys(client.getConfig().models || {}).length,
},
error: "具体错误信息",
steps: "重现步骤",
};
console.log("问题信息:", JSON.stringify(info, null, 2));
return info;
};
联系渠道
- 📧 技术支持邮箱 - 发送问题详情和系统信息
- 💬 内部技术群 - 快速获得社区帮助
- 📖 文档反馈 - 如发现文档问题,请反馈
常用检查命令
# 检查 SDK 版本
npm list @lovrabet/sdk
# 检查依赖冲突
npm ls --depth=0
# 清理缓存
npm cache clean --force
rm -rf node_modules package-lock.json
npm install
# 检查环境变量
echo $REACT_APP_LOVRABET_APP_CODE
📖 预防问题的最佳实践
- 使用 TypeScript - 编译时发现类型错误
- 错误边界 - 在 React 中使用错误边界组件
- 输入验证 - 验证用户输入和 API 响应
- 环境管理 - 区分开发和生产环境配置
- 监控日志 - 记录关键操作和错误信息
- 测试驱动 - 编写单元测试和集成测试
- 渐进部署 - 分阶段发布和测试功能
希望这些排查步骤能帮助您快速解决问题!如果仍有疑问,请联系技术支持团队。