错误处理
SDK 为不同的错误场景提供了类型化的异常类。
异常层次结构
text
NovelAIError (基类)
├── MissingAPIKeyError
├── AuthenticationError
├── InvalidRequestError
├── RateLimitError
├── ServerError
├── NetworkError
└── FileNotFoundError异常类型
NovelAIError
所有 SDK 错误的基类。
typescript
import { NovelAIError } from 'novelai-sdk-unofficial';
try {
// SDK 操作
} catch (error) {
if (error instanceof NovelAIError) {
console.error('SDK 错误:', error.message);
}
}MissingAPIKeyError
未提供 API Key 时抛出。
typescript
import { NovelAI, MissingAPIKeyError } from 'novelai-sdk-unofficial';
try {
const client = new NovelAI(); // 无 Key,无环境变量
} catch (error) {
if (error instanceof MissingAPIKeyError) {
console.error('请设置 NOVELAI_API_KEY 或提供 apiKey 选项');
}
}AuthenticationError
身份认证失败时抛出(HTTP 401、402)。
- API Key 无效
- API Key 已过期
- 积分/订阅不足
typescript
import { AuthenticationError } from 'novelai-sdk-unofficial';
try {
await client.image.generate({ prompt: 'test' });
} catch (error) {
if (error instanceof AuthenticationError) {
console.error('请检查 API Key 和订阅状态');
}
}InvalidRequestError
请求参数无效时抛出(HTTP 400)。
typescript
import { InvalidRequestError } from 'novelai-sdk-unofficial';
try {
await client.image.generate({
prompt: 'test',
size: [100, 100], // 无效:不是 64 的倍数
});
} catch (error) {
if (error instanceof InvalidRequestError) {
console.error('参数无效:', error.message);
}
}RateLimitError
超出速率限制时抛出(HTTP 429)。
typescript
import { RateLimitError } from 'novelai-sdk-unofficial';
try {
await client.image.generate({ prompt: 'test' });
} catch (error) {
if (error instanceof RateLimitError) {
console.error('请求过于频繁,请稍后重试');
// 实现退避策略
}
}ServerError
服务器端错误时抛出(HTTP 5xx)。
typescript
import { ServerError } from 'novelai-sdk-unofficial';
try {
await client.image.generate({ prompt: 'test' });
} catch (error) {
if (error instanceof ServerError) {
console.error('服务器错误,请稍后重试');
}
}NetworkError
网络相关故障时抛出。
- 连接超时
- DNS 解析失败
- 连接被拒绝
typescript
import { NetworkError } from 'novelai-sdk-unofficial';
try {
await client.image.generate({ prompt: 'test' });
} catch (error) {
if (error instanceof NetworkError) {
console.error('网络错误,请检查连接');
}
}FileNotFoundError
引用的文件不存在时抛出。
typescript
import { FileNotFoundError } from 'novelai-sdk-unofficial';
try {
// 如果使用的文件路径不存在
} catch (error) {
if (error instanceof FileNotFoundError) {
console.error('文件未找到:', error.message);
}
}完整的错误处理示例
typescript
import {
NovelAI,
NovelAIError,
MissingAPIKeyError,
AuthenticationError,
InvalidRequestError,
RateLimitError,
ServerError,
NetworkError,
} from 'novelai-sdk-unofficial';
async function generateImage(prompt: string) {
try {
const client = new NovelAI();
const images = await client.image.generate({ prompt });
return images[0];
} catch (error) {
if (error instanceof MissingAPIKeyError) {
throw new Error('配置错误:未设置 API Key');
}
if (error instanceof AuthenticationError) {
throw new Error('认证失败:请检查 API Key');
}
if (error instanceof InvalidRequestError) {
throw new Error(`请求无效:${error.message}`);
}
if (error instanceof RateLimitError) {
// 可以实现带退避的重试
throw new Error('请求过于频繁:请稍后重试');
}
if (error instanceof ServerError) {
throw new Error('服务器错误:服务暂时不可用');
}
if (error instanceof NetworkError) {
throw new Error('网络错误:请检查连接');
}
if (error instanceof NovelAIError) {
throw new Error(`SDK 错误:${error.message}`);
}
throw error; // 重新抛出未知错误
}
}重试策略
带指数退避的速率限制重试示例:
typescript
async function generateWithRetry(
prompt: string,
maxRetries: number = 3
): Promise<Buffer> {
let lastError: Error | undefined;
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
const images = await client.image.generate({ prompt });
return images[0];
} catch (error) {
if (error instanceof RateLimitError) {
lastError = error;
const delay = Math.pow(2, attempt) * 1000; // 1s, 2s, 4s
console.log(`请求受限,${delay}ms 后重试...`);
await new Promise(resolve => setTimeout(resolve, delay));
continue;
}
throw error; // 其他错误不重试
}
}
throw lastError;
}验证错误
SDK 使用 Zod 进行参数验证。无效参数会抛出 ZodError:
typescript
import { z } from 'zod';
try {
await client.image.generate({
prompt: '', // 空提示词
});
} catch (error) {
if (error instanceof z.ZodError) {
console.error('验证错误:');
error.errors.forEach(e => {
console.error(` ${e.path.join('.')}: ${e.message}`);
});
}
}