|
将脆弱的代码转变为生产就绪的弹性系统。
一个智能的错误处理助手,能够自动:
残酷的现实:
cuihua-error-handler 解决了所有这些问题。
告诉你的 OpenClaw 代理:
检查 src/ 中的错误处理覆盖率
代理将:
为 api/users.js 中的 getUserById 添加错误处理
代理将:
为支付服务添加熔断器
代理将:
自动发现缺失的错误处理:
javascript
// ❌ 之前 - 脆弱的代码
async function getUserById(id) {
const res = await fetch(/api/users/${id});
return res.json();
}
// 🔍 检测到的问题:
// - 没有处理网络故障
// - 没有处理非 200 响应
// - 没有处理无效 JSON
// - 没有用于调试的日志记录
生成生产就绪的错误处理:
javascript
// ✅ 之后 - 坚不可摧的代码
class UserServiceError extends Error {
constructor(message, options = {}) {
super(message);
this.name = UserServiceError;
this.statusCode = options.statusCode;
this.originalError = options.cause;
}
}
async function getUserById(id) {
try {
// 验证
if (!id || typeof id !== string) {
throw new UserServiceError(无效的用户 ID, { statusCode: 400 });
}
// 带超时的网络请求
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 5000);
const res = await fetch(/api/users/${id}, {
signal: controller.signal
});
clearTimeout(timeout);
// HTTP 错误处理
if (!res.ok) {
if (res.status === 404) {
throw new UserServiceError(用户 ${id} 未找到, { statusCode: 404 });
}
if (res.status >= 500) {
throw new UserServiceError(服务器错误,请重试, { statusCode: 502 });
}
throw new UserServiceError(HTTP ${res.status}, { statusCode: res.status });
}
// 带错误处理的 JSON 解析
let data;
try {
data = await res.json();
} catch (parseError) {
throw new UserServiceError(无效的响应格式, {
statusCode: 502,
cause: parseError
});
}
return data;
} catch (error) {
// 网络错误(超时、连接被拒绝)
if (error.name === AbortError) {
logger.error(getUserById 超时, { id, timeout: 5000 });
throw new UserServiceError(请求超时, {
statusCode: 504,
cause: error
});
}
if (error.message.includes(fetch failed)) {
logger.error(getUserById 网络错误, { id, error: error.message });
throw new UserServiceError(网络错误, {
statusCode: 503,
cause: error
});
}
// 重新抛出 UserServiceError
if (error instanceof UserServiceError) {
logger.error(getUserById 失败, { id, error: error.message });
throw error;
}
// 意外错误
logger.error(getUserById 意外错误, { id, error });
throw new UserServiceError(内部错误, {
statusCode: 500,
cause: error
});
}
}
带指数退避的智能重试:
javascript
async function retryWithBackoff(fn, options = {}) {
const {
maxRetries = 3,
initialDelay = 1000,
maxDelay = 10000,
backoffFactor = 2,
shouldRetry = (error) => true
} = options;
let lastError;
let delay = initialDelay;
for (let attempt = 0; attempt <= maxRetries; attempt++) {
try {
return await fn();
} catch (error) {
lastError = error;
// 检查是否应该重试
if (attempt === maxRetries || !shouldRetry(error)) {
throw error;
}
// 重试前等待
logger.warn(重试尝试 ${attempt + 1}/${maxRetries},等待 ${delay}ms, {
error: error.message
});
await new Promise(resolve => setTimeout(resolve, delay));
// 指数退避
delay = Math.min(delay * backoffFactor, maxDelay);
}
}
throw lastError;
}
// 使用示例
async function fetchUserWithRetry(id) {
return retryWithBackoff(
() => getUserById(id),
{
maxRetries: 3,
shouldRetry: (error) => {
// 在网络错误和 5xx 错误时重试
return error.statusCode >= 500 || error.name === NetworkError;
}
}
);
}
防止级联故障:
javascript
class CircuitBreaker {
constructor(fn, options = {}) {
this.fn = fn;
this.failureThreshold = options.failureThreshold || 5;
this.resetTimeout = options.resetTimeout || 60000;
this.state = CLOSED; // CLOSED, OPEN, HALF_OPEN
this.failureCount = 0;
this.nextAttempt = Date.now();
}
async execute(...args) {
if (this.state === OPEN) {
if (Date.now() < this.nextAttempt) {
throw new Error(熔断器已打开);
}
// 尝试恢复
this.state = HALF_OPEN;
}
try {
const result = await this.fn(...args);
this.onSuccess();
return result;
} catch (error) {
this.onFailure();
throw error;
}
}
onSuccess() {
this.failureCount = 0;
if (this.state === HALF_OPEN) {
this.state = CLOSED;
logger.info(熔断器已恢复);
}
}
onFailure() {
this.failureCount++;
if (this.failureCount >= this.failureThreshold) {
this.state = OPEN;
this.nextAttempt = Date.now() + this.resetTimeout;
logger.error(熔断器已打开, {
failureCount: this.failureCount,
resetTimeout: this.resetTimeout
});
}
}
}
// 使用示例
const getUserBreaker = new CircuitBreaker(getUserById, {
failureThreshold: 5,
resetTimeout: 60000
});
async function fetchUserSafely(id) {
try {
return await getUserBreaker.execute(id);
} catch (error) {
if (error.message === 熔断器已打开) {
// 返回缓存数据或默认值
return getCachedUser(id) || { id, name: 未知, error: true };
}
throw error;
}
}
回退到缓存/默认数据:
javascript
async function getUserWithFallback(id) {
try {
// 尝试主数据源
return await getUserById(id);
} catch (error) {
logger.warn(主数据源失败,尝试降级方案, { id, error: error.message });
try {
// 尝试缓存
const cached = await cache.get(
该技能支持在以下平台通过对话安装:
帮我安装 SkillHub 和 cuihua-error-handler-1776056583 技能
设置 SkillHub 为我的优先技能安装源,然后帮我安装 cuihua-error-handler-1776056583 技能
skillhub install cuihua-error-handler-1776056583
文件大小: 11.89 KB | 发布时间: 2026-4-14 13:10