瀏覽代碼

增加飞书通用错误码

cgp 2 天之前
父節點
當前提交
5ca0d8b109

+ 12 - 7
fs-service/src/main/java/com/fs/feishu/service/FeishuDocApiService.java

@@ -2,6 +2,7 @@ package com.fs.feishu.service;
 
 import com.fs.common.exception.CustomException;
 import com.fs.feishu.model.FeishuFileDTO;
+import com.fs.feishu.util.FeishuErrorCode;
 import com.lark.oapi.Client;
 import com.lark.oapi.service.docx.v1.model.*;
 import com.lark.oapi.service.drive.v1.model.DeleteFileReq;
@@ -45,15 +46,19 @@ public class FeishuDocApiService {
      * 检查 API 响应,若为账号级错误则禁用当前 Client 并抛出异常,否则只抛出业务异常
      */
     private void checkResponse(Client client, int code, String msg) {
-        if (code == 0) {
-            return;
-        }
-        if (isAccountError(code)) {
-            // 禁用该账号,禁用方法内部会抛出异常,流程不会继续
+        if (code == 0) return;
+
+        if (FeishuErrorCode.isAccountDisable(code)) {
             clientPool.disableClient(client, msg);
+            throw new CustomException("账号不可用: " + msg,code);
+        }
+        if (FeishuErrorCode.isRateLimit(code)) {
+            throw new CustomException("频率限制: " + msg,code);
+        }
+        if (FeishuErrorCode.isInternalRetryable(code)) {
+            throw new CustomException("内部错误: " + msg,code);
         }
-        // 非账号级别错误,直接抛出业务异常
-        throw new CustomException(String.format("飞书 API 错误: code=%d, msg=%s", code, msg));
+        throw new CustomException("飞书API错误: " + msg,code);
     }
 
     /**

+ 102 - 0
fs-service/src/main/java/com/fs/feishu/util/FeishuErrorCode.java

@@ -0,0 +1,102 @@
+package com.fs.feishu.util;
+
+import lombok.Getter;
+
+/**
+ * 飞书错误码枚举,按处理策略分类
+ */
+@Getter
+public enum FeishuErrorCode {
+
+    // ========== 账号级错误(需要禁用应用) ==========
+    ACCOUNT_DISABLE_10012(10012, ErrorCategory.ACCOUNT_DISABLE, "获取App Token失败"),
+    ACCOUNT_DISABLE_10014(10014, ErrorCategory.ACCOUNT_DISABLE, "应用状态不可用"),
+    ACCOUNT_DISABLE_10015(10015, ErrorCategory.ACCOUNT_DISABLE, "App Secret错误"),
+    ACCOUNT_DISABLE_99991662(99991662, ErrorCategory.ACCOUNT_DISABLE, "应用已停用"),
+    ACCOUNT_DISABLE_99991673(99991673, ErrorCategory.ACCOUNT_DISABLE, "应用未授权"),
+
+    // ========== 频率限制错误 ==========
+    RATE_LIMIT_99991400(99991400, ErrorCategory.RATE_LIMIT, "请求频率超限"),
+    RATE_LIMIT_1000004(1000004, ErrorCategory.RATE_LIMIT, "接口限流"),
+    RATE_LIMIT_1000005(1000005, ErrorCategory.RATE_LIMIT, "应用限流"),
+    RATE_LIMIT_11232(11232, ErrorCategory.RATE_LIMIT, "创建消息触发系统限流"),
+    RATE_LIMIT_11233(11233, ErrorCategory.RATE_LIMIT, "创建消息触发群限流"),
+    RATE_LIMIT_11247(11247, ErrorCategory.RATE_LIMIT, "内部发送消息触发频控"),
+
+    // ========== 内部可重试错误 ==========
+    INTERNAL_RETRY_1500(1500, ErrorCategory.INTERNAL_RETRYABLE, "内部错误"),
+    INTERNAL_RETRY_1503(1503, ErrorCategory.INTERNAL_RETRYABLE, "Token鉴权内部错误"),
+    INTERNAL_RETRY_1551(1551, ErrorCategory.INTERNAL_RETRYABLE, "获取tenant id错误"),
+    INTERNAL_RETRY_1642(1642, ErrorCategory.INTERNAL_RETRYABLE, "更新session失败"),
+    INTERNAL_RETRY_1663(1663, ErrorCategory.INTERNAL_RETRYABLE, "内部错误"),
+    INTERNAL_RETRY_1665(1665, ErrorCategory.INTERNAL_RETRYABLE, "内部错误"),
+    INTERNAL_RETRY_1668(1668, ErrorCategory.INTERNAL_RETRYABLE, "内部错误"),
+    INTERNAL_RETRY_2200(2200, ErrorCategory.INTERNAL_RETRYABLE, "内部服务错误"),
+    INTERNAL_RETRY_5000(5000, ErrorCategory.INTERNAL_RETRYABLE, "内部错误"),
+    INTERNAL_RETRY_55001(55001, ErrorCategory.INTERNAL_RETRYABLE, "服务内部错误"),
+    INTERNAL_RETRY_10500(10500, ErrorCategory.INTERNAL_RETRYABLE, "服务端异常"),
+    INTERNAL_RETRY_99991663(99991663, ErrorCategory.INTERNAL_RETRYABLE, "无效token"),
+
+    // ========== 常见业务错误(不可重试) ==========
+    BUSINESS_ERROR_600(600, ErrorCategory.BUSINESS_ERROR, "资源被删除"),
+    BUSINESS_ERROR_1002(1002, ErrorCategory.BUSINESS_ERROR, "文档已删除"),
+    BUSINESS_ERROR_4000(4000, ErrorCategory.BUSINESS_ERROR, "请求参数错误"),
+    BUSINESS_ERROR_4001(4001, ErrorCategory.BUSINESS_ERROR, "Token无效"),
+    BUSINESS_ERROR_4004(4004, ErrorCategory.BUSINESS_ERROR, "用户不存在"),
+    BUSINESS_ERROR_10001(10001, ErrorCategory.BUSINESS_ERROR, "请求参数无效"),
+    BUSINESS_ERROR_10006(10006, ErrorCategory.BUSINESS_ERROR, "资源不存在"),
+
+    // 未知错误
+    UNKNOWN(-1, ErrorCategory.UNKNOWN, "未知错误");
+
+    private final int code;
+    private final ErrorCategory category;
+    private final String defaultMsg;
+
+    FeishuErrorCode(int code, ErrorCategory category, String defaultMsg) {
+        this.code = code;
+        this.category = category;
+        this.defaultMsg = defaultMsg;
+    }
+
+    /**
+     * 根据错误码查找对应枚举,若未找到则返回 UNKNOWN
+     */
+    public static FeishuErrorCode fromCode(int code) {
+        for (FeishuErrorCode e : values()) {
+            if (e.code == code) {
+                return e;
+            }
+        }
+        return UNKNOWN;
+    }
+
+    /**
+     * 是否为账号级错误(需要禁用应用)
+     */
+    public static boolean isAccountDisable(int code) {
+        return fromCode(code).getCategory() == ErrorCategory.ACCOUNT_DISABLE;
+    }
+
+    /**
+     * 是否为频率限制错误
+     */
+    public static boolean isRateLimit(int code) {
+        return fromCode(code).getCategory() == ErrorCategory.RATE_LIMIT;
+    }
+
+    /**
+     * 是否为内部可重试错误
+     */
+    public static boolean isInternalRetryable(int code) {
+        return fromCode(code).getCategory() == ErrorCategory.INTERNAL_RETRYABLE;
+    }
+
+    public enum ErrorCategory {
+        ACCOUNT_DISABLE,   // 账号级错误,需禁用
+        RATE_LIMIT,        // 频率限制,需等待后重试
+        INTERNAL_RETRYABLE,// 内部错误,可重试
+        BUSINESS_ERROR,    // 业务错误,不重试
+        UNKNOWN            // 未知
+    }
+}