# openclaw 错误处理最佳实践
在使用 openclaw 过程中,错误处理是确保系统稳定性和用户体验的重要环节。本文将详细介绍 openclaw 的错误处理机制、常见问题及最佳实践。
## 错误处理基础
### 1. 错误类型
**常见错误类型**:
– API 错误:接口调用失败
– 认证错误:权限验证失败
– 数据错误:数据验证失败
– 系统错误:服务内部错误
– 网络错误:网络连接问题
– 配置错误:配置参数错误
### 2. 错误码系统
**错误码结构**:
– 业务错误码:4xx 系列
– 系统错误码:5xx 系列
– 自定义错误码:特定业务场景
**示例错误码**:
– 400:请求参数错误
– 401:未授权
– 403:禁止访问
– 404:资源不存在
– 500:内部服务器错误
– 503:服务不可用
## 常见错误处理问题及解决方案
### 1. 错误信息不明确
**症状**:
– 错误信息模糊
– 错误码与实际问题不符
– 缺少详细的错误描述
**解决方案**:
“`javascript
// 统一错误处理中间件
app.use((err, req, res, next) => {
let statusCode = 500;
let errorCode = ‘INTERNAL_SERVER_ERROR’;
let message = ‘Internal server error’;
if (err.name === ‘ValidationError’) {
statusCode = 400;
errorCode = ‘VALIDATION_ERROR’;
message = Object.values(err.errors).map(e => e.message).join(‘, ‘);
} else if (err.name === ‘UnauthorizedError’) {
statusCode = 401;
errorCode = ‘UNAUTHORIZED’;
message = ‘Authentication required’;
} else if (err.name === ‘ForbiddenError’) {
statusCode = 403;
errorCode = ‘FORBIDDEN’;
message = ‘Access denied’;
} else if (err.name === ‘NotFoundError’) {
statusCode = 404;
errorCode = ‘NOT_FOUND’;
message = ‘Resource not found’;
} else if (err.code) {
// 自定义错误
statusCode = err.statusCode || 500;
errorCode = err.code;
message = err.message || ‘Internal server error’;
}
res.status(statusCode).json({
error: {
code: errorCode,
message: message,
timestamp: new Date().toISOString(),
path: req.path
}
});
});
“`
### 2. 错误日志不完整
**症状**:
– 错误日志缺少上下文信息
– 无法追踪错误发生的原因
– 错误日志格式不统一
**解决方案**:
“`javascript
// 错误日志配置
const logger = winston.createLogger({
level: ‘error’,
format: winston.format.combine(
winston.format.timestamp(),
winston.format.json(),
winston.format.errors({ stack: true })
),
defaultMeta: { service: ‘openclaw’ },
transports: [
new winston.transports.File({ filename: ‘error.log’, level: ‘error’ }),
new winston.transports.Console({ format: winston.format.simple() })
]
});
// 错误日志中间件
app.use((err, req, res, next) => {
logger.error(‘Error occurred’, {
error: err.message,
stack: err.stack,
path: req.path,
method: req.method,
headers: req.headers,
body: req.body,
query: req.query,
params: req.params,
ip: req.ip
});
next(err);
});
“`
### 3. 错误处理逻辑重复
**症状**:
– 错误处理代码重复
– 维护困难
– 一致性差
**解决方案**:
“`javascript
// 错误处理工具类
class ErrorHandler {
static handle(err, req, res) {
const errorResponse = this.formatError(err);
res.status(errorResponse.statusCode).json(errorResponse.body);
}
static formatError(err) {
switch (err.name) {
case ‘ValidationError’:
return {
statusCode: 400,
body: {
error: {
code: ‘VALIDATION_ERROR’,
message: Object.values(err.errors).map(e => e.message).join(‘, ‘)
}
}
};
case ‘UnauthorizedError’:
return {
statusCode: 401,
body: {
error: {
code: ‘UNAUTHORIZED’,
message: ‘Authentication required’
}
}
};
// 其他错误类型…
default:
return {
statusCode: err.statusCode || 500,
body: {
error: {
code: err.code || ‘INTERNAL_SERVER_ERROR’,
message: err.message || ‘Internal server error’
}
}
};
}
}
}
// 使用示例
app.use((err, req, res, next) => {
ErrorHandler.handle(err, req, res);
});
“`
### 4. 错误恢复机制缺失
**症状**:
– 系统因错误而崩溃
– 无法自动恢复
– 错误影响范围扩大
**解决方案**:
“`javascript
// 进程错误处理
process.on(‘uncaughtException’, (err) => {
logger.error(‘Uncaught Exception’, { error: err.message, stack: err.stack });
// 执行必要的清理操作
process.exit(1); // 退出进程,让进程管理器重启
});
process.on(‘unhandledRejection’, (reason, promise) => {
logger.error(‘Unhandled Rejection’, { reason, promise });
});
// 服务错误处理
app.use(async (err, req, res, next) => {
try {
// 记录错误
logger.error(‘Request Error’, { error: err.message, stack: err.stack, path: req.path });
// 尝试恢复
if (err.code === ‘DATABASE_ERROR’) {
// 尝试重新连接数据库
await db.reconnect();
logger.info(‘Database reconnected successfully’);
}
// 返回错误响应
ErrorHandler.handle(err, req, res);
} catch (recoveryError) {
logger.error(‘Recovery failed’, { error: recoveryError.message });
res.status(500).json({
error: {
code: ‘RECOVERY_FAILED’,
message: ‘Failed to recover from error’
}
});
}
});
“`
## 错误处理最佳实践
### 1. 统一错误响应格式
– **标准格式**:使用统一的错误响应结构
– **包含必要信息**:错误码、错误消息、时间戳、请求路径
– **国际化支持**:支持多语言错误消息
**示例响应**:
“`json
{
“error”: {
“code”: “VALIDATION_ERROR”,
“message”: “Email format is invalid”,
“timestamp”: “2023-12-01T10:30:00Z”,
“path”: “/api/users”
}
}
“`
### 2. 分层错误处理
– **应用层**:处理业务逻辑错误
– **中间件层**:处理通用错误
– **系统层**:处理系统级错误
– **客户端**:处理客户端错误
### 3. 错误预防
– **输入验证**:严格验证输入参数
– **异常捕获**:捕获可能的异常
– **边界检查**:检查边界条件
– **资源管理**:正确管理资源
### 4. 错误监控
– **实时监控**:监控错误发生频率
– **告警机制**:设置错误告警阈值
– **错误分析**:分析错误模式和原因
– **趋势分析**:跟踪错误趋势
## 常见错误场景及解决方案
### 1. API 调用错误
**场景**:API 调用返回错误
**解决方案**:
“`javascript
// API 调用错误处理
async function callApi(endpoint, options) {
try {
const response = await fetch(endpoint, options);
if (!response.ok) {
const errorData = await response.json();
throw new Error(errorData.error?.message || `API error: ${response.status}`);
}
return await response.json();
} catch (error) {
if (error.name === ‘FetchError’) {
throw new Error(‘Network error: Unable to connect to API’);
}
throw error;
}
}
// 使用示例
try {
const data = await callApi(‘https://api.openclaw.io/api/users’, {
method: ‘POST’,
headers: { ‘Content-Type’: ‘application/json’ },
body: JSON.stringify({ name: ‘Test’, email: ‘test@example.com’ })
});
console.log(‘Success:’, data);
} catch (error) {
console.error(‘Error:’, error.message);
// 处理错误
}
“`
### 2. 数据库错误
**场景**:数据库操作失败
**解决方案**:
“`javascript
// 数据库错误处理
async function executeQuery(query, params) {
let connection;
try {
connection = await pool.getConnection();
const result = await connection.query(query, params);
return result;
} catch (error) {
if (error.code === ‘ER_DUP_ENTRY’) {
throw new Error(‘Duplicate entry: Record already exists’);
} else if (error.code === ‘ER_NO_SUCH_TABLE’) {
throw new Error(‘Database table does not exist’);
} else if (error.code === ‘ER_ACCESS_DENIED_ERROR’) {
throw new Error(‘Database access denied’);
}
throw new Error(`Database error: ${error.message}`);
} finally {
if (connection) {
connection.release();
}
}
}
“`
### 3. 业务逻辑错误
**场景**:业务逻辑验证失败
**解决方案**:
“`javascript
// 业务逻辑错误处理
class BusinessError extends Error {
constructor(code, message, statusCode = 400) {
super(message);
this.name = ‘BusinessError’;
this.code = code;
this.statusCode = statusCode;
}
}
// 使用示例
function processOrder(order) {
if (!order.items || order.items.length === 0) {
throw new BusinessError(‘EMPTY_ORDER’, ‘Order must contain at least one item’);
}
if (order.total <= 0) {
throw new BusinessError('INVALID_TOTAL', 'Order total must be greater than zero');
}
// 处理订单逻辑
return { success: true, orderId: generateOrderId() };
}
try {
const result = processOrder({ items: [], total: 0 });
console.log('Order processed:', result);
} catch (error) {
if (error instanceof BusinessError) {
console.error('Business error:', error.code, error.message);
// 处理业务错误
} else {
console.error('Unexpected error:', error.message);
// 处理其他错误
}
}
```
## 错误处理工具集成
### 1. 与 Sentry 集成
```javascript
// Sentry 集成
const Sentry = require('@sentry/node');
Sentry.init({
dsn: 'https://your-sentry-dsn@sentry.io/12345',
environment: process.env.NODE_ENV,
release: '1.0.0'
});
// 错误捕获中间件
app.use(Sentry.Handlers.errorHandler());
// 手动捕获错误
try {
// 代码逻辑
} catch (error) {
Sentry.captureException(error);
// 处理错误
}
```
### 2. 与 ELK Stack 集成
```javascript
// ELK Stack 集成
const winston = require('winston');
const Elasticsearch = require('winston-elasticsearch');
const esTransportOpts = {
level: 'error',
clientOpts: {
node: 'http://elasticsearch:9200'
},
indexPrefix: 'openclaw-errors'
};
const logger = winston.createLogger({
transports: [
new Elasticsearch(esTransportOpts),
new winston.transports.Console()
]
});
// 错误日志记录
app.use((err, req, res, next) => {
logger.error(‘Error occurred’, {
error: err.message,
stack: err.stack,
path: req.path,
method: req.method
});
next(err);
});
“`
## 故障排除
### 1. 错误定位
“`bash
# 查看错误日志
journalctl -u openclaw | grep error
# 查看应用日志
cat /var/log/openclaw/error.log
# 查看API错误
curl -X GET https://api.openclaw.io/api/health
# 检查数据库连接
openclaw config test db
“`
### 2. 错误重现
“`bash
# 重现API错误
curl -X POST https://api.openclaw.io/api/users \
-H “Content-Type: application/json” \
-d ‘{“name”: “”, “email”: “invalid-email”}’
# 测试数据库操作
openclaw db query “SELECT * FROM users WHERE id = 1”
# 检查配置
openclaw config validate
“`
### 3. 错误分析
“`bash
# 分析错误日志
cat /var/log/openclaw/error.log | grep -E “ERROR|ValidationError|DatabaseError”
# 统计错误类型
cat /var/log/openclaw/error.log | grep -o “code.*” | sort | uniq -c
# 查看最近的错误
tail -n 100 /var/log/openclaw/error.log | grep ERROR
“`
## 总结
通过正确实施错误处理最佳实践,可以显著提高 openclaw 系统的稳定性和可靠性。以下是一些关键要点:
– **统一错误响应格式**:确保错误信息清晰一致
– **分层错误处理**:在不同层级处理不同类型的错误
– **完善错误日志**:记录详细的错误信息和上下文
– **错误预防**:通过输入验证和边界检查预防错误
– **错误监控**:实时监控错误发生情况
– **自动恢复**:实现错误后的自动恢复机制
– **工具集成**:与错误监控工具集成
通过以上措施,可以建立一个健壮的错误处理系统,为 openclaw 的稳定运行提供有力保障。