| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280 |
- /**
- * 错误处理工具
- *
- * 提供统一的错误处理和用户友好的错误提示
- */
- export interface ErrorDetail {
- code?: string;
- message: string;
- title?: string;
- solution?: string;
- actions?: Array<{
- label: string;
- onClick: () => void;
- }>;
- }
- /**
- * DashScope API 错误映射
- */
- const DASHSCOPE_ERROR_MAP: Record<string, ErrorDetail> = {
- 'App.AccessDenied': {
- title: 'API Key 权限不足',
- message: '您的 API Key 没有访问 Deep Research 的权限',
- solution: '请在阿里云百炼控制台开通 Deep Research 功能,或重新生成包含该权限的 API Key',
- },
- 'InvalidParameter': {
- title: '请求参数错误',
- message: '请求参数不正确',
- solution: '请检查输入内容是否符合要求,或联系技术支持',
- },
- 'QuotaExceeded': {
- title: 'API 调用配额已用尽',
- message: '您的 API 调用配额已达到上限',
- solution: '请充值或等待配额重置,也可以升级套餐获得更多配额',
- },
- 'Throttling': {
- title: '请求过于频繁',
- message: '您的请求速度超过了限制',
- solution: '请稍后再试,或联系客服提升限流阈值',
- },
- 'InternalError': {
- title: '服务内部错误',
- message: 'DashScope 服务遇到内部错误',
- solution: '请稍后重试,如果问题持续存在,请联系技术支持',
- },
- 'ServiceUnavailable': {
- title: '服务暂时不可用',
- message: 'DashScope 服务暂时无法访问',
- solution: '请稍后重试,或查看服务状态页面',
- },
- };
- /**
- * 通用错误映射
- */
- const COMMON_ERROR_MAP: Record<string, ErrorDetail> = {
- 'NetworkError': {
- title: '网络连接失败',
- message: '无法连接到服务器',
- solution: '请检查网络连接,或稍后重试',
- },
- 'Timeout': {
- title: '请求超时',
- message: '服务器响应超时',
- solution: '请检查网络连接,或稍后重试',
- },
- 'Unauthorized': {
- title: '未授权',
- message: '您的登录已过期',
- solution: '请重新登录',
- },
- 'Forbidden': {
- title: '访问被拒绝',
- message: '您没有权限执行此操作',
- solution: '请联系管理员获取权限',
- },
- 'NotFound': {
- title: '资源不存在',
- message: '请求的资源未找到',
- solution: '请检查请求是否正确',
- },
- };
- /**
- * 解析错误信息
- */
- export function parseError(error: any): ErrorDetail {
- // 如果是字符串,直接返回
- if (typeof error === 'string') {
- return {
- message: error,
- };
- }
- // 如果是 Error 对象
- if (error instanceof Error) {
- // 尝试解析错误消息中的错误代码
- const errorMessage = error.message;
-
- // axios 错误常包含 response 对象,优先解析
- // 处理 axios 风格的错误对象
- // @ts-ignore
- if ((error as any).response) {
- // @ts-ignore
- const resp = (error as any).response;
- const msg = resp.data?.message || resp.data?.detail;
- if (msg) {
- return {
- message: msg,
- };
- }
- }
- // 检查是否包含 DashScope 错误代码
- for (const [code, detail] of Object.entries(DASHSCOPE_ERROR_MAP)) {
- if (errorMessage.includes(code)) {
- return {
- code,
- ...detail,
- };
- }
- }
-
- // 检查是否包含通用错误
- for (const [code, detail] of Object.entries(COMMON_ERROR_MAP)) {
- if (errorMessage.includes(code) || errorMessage.toLowerCase().includes(code.toLowerCase())) {
- return {
- code,
- ...detail,
- };
- }
- }
-
- // 返回原始错误消息
- return {
- message: errorMessage,
- };
- }
- // 如果是对象,尝试提取错误信息
- if (typeof error === 'object' && error !== null) {
- // axios 风格的错误体可能包含 response
- // @ts-ignore
- if (error.response) {
- // @ts-ignore
- const resp = error.response;
- const msg = resp.data?.message || resp.data?.detail;
- if (msg) {
- return {
- message: msg,
- };
- }
- }
- const code = error.code || error.error_code;
- const message = error.message || error.error_message || error.msg;
-
- // 检查是否是已知的错误代码
- if (code && DASHSCOPE_ERROR_MAP[code]) {
- return {
- code,
- ...DASHSCOPE_ERROR_MAP[code],
- };
- }
-
- if (code && COMMON_ERROR_MAP[code]) {
- return {
- code,
- ...COMMON_ERROR_MAP[code],
- };
- }
-
- // 返回提取的信息
- return {
- code,
- message: message || '未知错误',
- };
- }
- // 默认错误
- return {
- message: '发生未知错误',
- };
- }
- /**
- * 格式化错误消息(用于 Toast 显示)
- */
- export function formatErrorMessage(error: any): string {
- const detail = parseError(error);
-
- if (detail.title) {
- return `${detail.title}: ${detail.message}`;
- }
-
- return detail.message;
- }
- /**
- * 获取错误的完整信息(用于详细展示)
- */
- export function getErrorDetail(error: any): ErrorDetail {
- return parseError(error);
- }
- /**
- * 判断是否是 API Key 权限错误
- */
- export function isApiKeyPermissionError(error: any): boolean {
- const detail = parseError(error);
- return detail.code === 'App.AccessDenied';
- }
- /**
- * 判断是否是网络错误
- */
- export function isNetworkError(error: any): boolean {
- const detail = parseError(error);
- return detail.code === 'NetworkError' ||
- detail.code === 'Timeout' ||
- detail.message.includes('network') ||
- detail.message.includes('timeout');
- }
- /**
- * 获取错误的建议操作
- */
- export function getErrorActions(error: any, navigate?: (path: string) => void): Array<{
- label: string;
- onClick: () => void;
- }> {
- const detail = parseError(error);
- const actions: Array<{ label: string; onClick: () => void }> = [];
-
- // API Key 权限错误
- if (detail.code === 'App.AccessDenied') {
- actions.push({
- label: '查看解决方案',
- onClick: () => {
- window.open('https://help.aliyun.com/zh/model-studio/', '_blank');
- },
- });
-
- if (navigate) {
- actions.push({
- label: '更新 API Key',
- onClick: () => navigate('/settings'),
- });
- }
- }
-
- // 配额用尽
- if (detail.code === 'QuotaExceeded') {
- actions.push({
- label: '查看配额',
- onClick: () => {
- window.open('https://bailian.console.aliyun.com/', '_blank');
- },
- });
- }
-
- return actions;
- }
- /**
- * 创建用户友好的错误对话框配置
- */
- export function createErrorDialog(error: any, navigate?: (path: string) => void) {
- const detail = getErrorDetail(error);
- const actions = getErrorActions(error, navigate);
-
- return {
- title: detail.title || '错误',
- message: detail.message,
- solution: detail.solution,
- actions,
- };
- }
|