故障排查
本文提供 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);
};
🔧 filter 多表查询问题
Q14: filter 多表查询没有返回关联数据
问题描述:使用点号语法查询关联表,但返回的数据中没有关联字段
解决方案:
// 1. 检查关联关系是否已配置
// 在 Lovrabet 工作台的 ER 图中确认表关联关系
// 地址: https://app.lovrabet.com/app/{appCode}/data/er
// 2. 确认字段名格式正确
const result = await client.models.orders.filter({
select: [
'id',
'customer.name', // ✅ 正确:使用表名.字段名
],
where: {
'customer.level': { $eq: 'VIP' } // ✅ where 中也使用点号语法
}
});
// 3. 检查返回结构
console.log(result.tableData[0]);
// { id: 1, customer: { name: '张三', level: 'VIP' } }
// 4. 常见错误排查
// ❌ 错误:使用 datasetCode 而非表名
// 'dataset_customer.name'
// ❌ 错误:字段名拼写错误
// 'customers.name' // 如果表名是 customer 而非 customers
Q15: filter 多表查询报错 "关系不存在"
问题描述:提示表之间没有关联关系
解决方案:
// 1. 检查表名是否正确
// 使用数据库表名,不是 datasetCode
// ❌ 错误:dataset_8d2dcbae08b54bdd84c00be558ed48df
// ✅ 正确:customer / customers
// 2. 在 ER 图中手动添加关联关系
// 访问: https://app.lovrabet.com/app/{appCode}/data/er
// 选择两表 → 设置关联字段 → 保存
// 3. 确认关联方向
// 1:1 和 N:1 关系支持自动查询
// 1:N 关系需要从 N 端查询(例如:订单查询客户,不是客户查询订单)
// 4. 检查关联字段是否存在
// 确保外键字段在数据库中存在
Q16: filter where 条件中的关联字段不生效
问题描述:使用关联字段过滤没有效果
解决方案:
// 1. 确认使用点号语法
const result = await client.models.orders.filter({
where: {
// ✅ 正确
'customer.level': { $eq: 'VIP' },
// ❌ 错误:不能直接使用对象
customer: { level: { $eq: 'VIP' } }
}
});
// 2. 关联字段过滤需要在 select 中声明
const result = await client.models.orders.filter({
select: [
'id',
'customer.level' // 需要包含这个字段
],
where: {
'customer.level': { $eq: 'VIP' }
}
});
// 3. 检查关联表是否有数据
// 先不使用 where 条件查询,确认关联数据存在
const testResult = await client.models.orders.filter({
select: ['id', 'customer.level'],
pageSize: 5
});
console.log(testResult.tableData);
🧩 模型配置问题
Q17: 模型别名不生效
问题描述:配置了别名但无法使用
解决方案:
// 1. 检查配置是否正确导入
import { registerModels, createClient } from '@lovrabet/sdk';
import { LOVRABET_MODELS_CONFIG } from './api/api';
// ✅ 确保先注册配置
registerModels(LOVRABET_MODELS_CONFIG);
// 2. 验证别名是否注册成功
const client = createClient();
const models = client.getModelListDetails();
console.log(models);
// [
// { datasetCode: 'xxx', tableName: 'users', alias: 'users' }
// ]
// 3. 使用正确的访问方式
// 标准方式(始终可用)
await client.models.dataset_8d2dcbae08b54bdd84c00be558ed48df.filter();
// 别名方式(需要配置)
await client.models.users.filter();
// 4. 如果别名丢失,手动添加
client.addModel({
datasetCode: '8d2dcbae08b54bdd84c00be558ed48df',
tableName: 'users',
alias: 'users'
});
Q18: TypeScript 类型报错 "Property does not exist"
问题描述:TypeScript 提示模型属性不存在
解决方案:
// 1. 确保 tsconfig.json 配置正确
{
"compilerOptions": {
"moduleResolution": "node",
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"skipLibCheck": true
}
}
// 2. 检查 SDK 版本
npm list @lovrabet/sdk
// 3. 使用类型断言(临时方案)
const client = createClient();
const models = client.models as any;
await models.users.filter();
// 4. 定义类型接口(推荐)
interface User {
id: number;
name: string;
email: string;
}
const result = await client.models.users.filter();
const users = result.tableData as User[];
📦 构建和部署问题
Q19: 生产环境打包后请求失败
问题描述:开发环境正常,生产环境打包后无法访问 API
解决方案:
// 1. 检查环境变量配置
// .env.production
REACT_APP_LOVRABET_APP_CODE=your-app-code
REACT_APP_LOVRABET_ENV=production
// 2. 确认 API 地址
const client = createClient({
appCode: process.env.REACT_APP_LOVRABET_APP_CODE,
options: {
serverUrl: process.env.REACT_APP_LOVRABET_ENV === 'production'
? 'https://api.lovrabet.com'
: 'https://dev-api.lovrabet.com'
}
});
// 3. 检查 CORS 配置
// 确保生产域名已添加到 CORS 白名单
// 4. Cookie 认证需要配置域名
const client = createClient({
options: {
withCredentials: true,
// 生产环境需要同源或正确配置 CORS
}
});
Q20: Vite 构建报错
问题描述:使用 Vite 构建时遇到 SDK 相关错误
解决方案:
// 1. 检查 vite.config.ts
export default defineConfig({
// ... 其他配置
optimizeDeps: {
include: ['@lovrabet/sdk']
},
build: {
commonjsOptions: {
include: [/node_modules\/@lovrabet/]
}
}
});
// 2. 清理缓存重新构建
rm -rf node_modules/.vite
npm run build
// 3. 检查 Node.js 版本
node --version # 需要 >= 18
🔍 调试工具和技巧
调试助手类
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 响应
- 环境管理 - 区分开发和生产环境配置
- 监控日志 - 记录关键操作和错误信息
- 测试驱动 - 编写单元测试和集成测试
- 渐进部署 - 分阶段发布和测试功能
希望这些排查步骤能帮助您快速解决问题!如果仍有疑问,请联系技术支持团队。