跳到主要内容

故障排查

本文提供 Lovrabet SDK 常见问题的解决方案,帮助您快速诊断和修复问题。

🔧 常见问题诊断

问题诊断流程

在遇到问题时,请按以下步骤进行排查:

  1. 检查错误信息 - 查看控制台错误日志
  2. 验证配置 - 确认 SDK 配置正确
  3. 检查网络 - 查看网络请求状态
  4. 验证权限 - 确认 API 访问权限
  5. 查看文档 - 对照本文档检查用法

启用详细日志

// 启用详细的错误日志
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");
}

问题描述:在浏览器中 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

📖 预防问题的最佳实践

  1. 使用 TypeScript - 编译时发现类型错误
  2. 错误边界 - 在 React 中使用错误边界组件
  3. 输入验证 - 验证用户输入和 API 响应
  4. 环境管理 - 区分开发和生产环境配置
  5. 监控日志 - 记录关键操作和错误信息
  6. 测试驱动 - 编写单元测试和集成测试
  7. 渐进部署 - 分阶段发布和测试功能

希望这些排查步骤能帮助您快速解决问题!如果仍有疑问,请联系技术支持团队。