This commit is contained in:
2026-07-27 00:03:07 +08:00
parent 7244df5ae1
commit c3b0de6ac5
7 changed files with 281 additions and 48 deletions

View File

@@ -77,7 +77,7 @@ func (c *Client) GenerateEnterpriseAuth(req *EnterpriseAuthRequest) (*Enterprise
return nil, err
}
if res.Code != successCode {
return nil, fmt.Errorf("获取法大大企业认证链接失败: code=%s msg=%s requestId=%s", res.Code, res.Msg, res.RequestID)
return nil, NewAPIError("获取法大大企业认证链接失败", res.Code, res.Msg, res.RequestID)
}
var data getCorpAuthURLData
@@ -128,7 +128,7 @@ func (c *Client) QueryOrgIdentity(req *QueryOrgIdentityRequest) (*QueryOrgIdenti
return nil, err
}
if res.Code != successCode {
return nil, fmt.Errorf("查询法大大企业实名状态失败: code=%s msg=%s requestId=%s", res.Code, res.Msg, res.RequestID)
return nil, NewAPIError("查询法大大企业实名状态失败", res.Code, res.Msg, res.RequestID)
}
var data getIdentifiedStatusData

View File

@@ -0,0 +1,89 @@
package fadada
import (
"errors"
"fmt"
"regexp"
"strings"
)
// 法大大 FASC OpenAPI 错误码(以官方「错误码说明」文档 code 为准,勿依赖 msg 文案)。
// 文档https://dev.fadada.com/api-doc/JOQQIJXLFL/H4F0HSKMHQ3HPIIM/5-1
const (
CodeSuccess = "100000" // 请求成功
// 公共
CodeUnknownException = "100001" // 不可预知异常
CodeAccessTokenInvalid = "100002" // 访问凭证失效
CodeSignInvalid = "100003" // 接口签名错误
CodeTooFrequent = "100004" // 请求频繁
CodeParamIllegal = "100011" // 请求参数非法
CodeParamEmpty = "100012" // 请求参数为空
CodeBusinessIDNotFound = "212007" // 业务场景标识不存在
// 授权范围重复获取:主体已对本应用授权,无须再获取授权链接
// 个人用户帐号管理 / 企业用户帐号管理 均有说明
CodeAuthScopeDuplicate = "210002" // 授权范围重复获取
CodeAuthScopeDuplicateCorp = "210013" // 授权范围重复获取(无须重复获取授权申请链接)
)
// APIError 法大大业务错误(按 code 判断,不依赖 msg
type APIError struct {
Op string // 调用场景说明
Code string
Msg string
RequestID string
}
func (e *APIError) Error() string {
if e == nil {
return ""
}
op := strings.TrimSpace(e.Op)
if op == "" {
op = "法大大接口调用失败"
}
return fmt.Sprintf("%s: code=%s msg=%s requestId=%s", op, e.Code, e.Msg, e.RequestID)
}
// NewAPIError 构造结构化业务错误
func NewAPIError(op, code, msg, requestID string) *APIError {
return &APIError{
Op: strings.TrimSpace(op),
Code: strings.TrimSpace(code),
Msg: strings.TrimSpace(msg),
RequestID: strings.TrimSpace(requestID),
}
}
// IsAuthAlreadyGranted 是否表示「已授权 / 授权范围重复获取」,应跳过再次获取授权链接。
// 官方文档:应按返回码 code 判断msg 可能调整。
func IsAuthAlreadyGranted(err error) bool {
if err == nil {
return false
}
var apiErr *APIError
if errors.As(err, &apiErr) && apiErr != nil {
return isAuthAlreadyGrantedCode(apiErr.Code)
}
return isAuthAlreadyGrantedCode(extractFadadaCode(err.Error()))
}
func isAuthAlreadyGrantedCode(code string) bool {
switch strings.TrimSpace(code) {
case CodeAuthScopeDuplicate, CodeAuthScopeDuplicateCorp:
return true
default:
return false
}
}
var fadadaCodeRe = regexp.MustCompile(`(?i)(?:^|[^\d])code\s*=\s*(\d{6})(?:[^\d]|$)`)
func extractFadadaCode(msg string) string {
m := fadadaCodeRe.FindStringSubmatch(msg)
if len(m) < 2 {
return ""
}
return m[1]
}

View File

@@ -0,0 +1,28 @@
package fadada
import (
"errors"
"fmt"
"testing"
)
func TestIsAuthAlreadyGranted(t *testing.T) {
if !IsAuthAlreadyGranted(NewAPIError("op", CodeAuthScopeDuplicate, "授权范围重复获取", "1")) {
t.Fatal("210002 should match")
}
if !IsAuthAlreadyGranted(NewAPIError("op", CodeAuthScopeDuplicateCorp, "授权范围重复获取", "2")) {
t.Fatal("210013 should match")
}
if IsAuthAlreadyGranted(NewAPIError("op", CodeParamIllegal, "请求参数非法", "3")) {
t.Fatal("100011 should not match")
}
if !IsAuthAlreadyGranted(fmt.Errorf("wrap: %w", NewAPIError("op", CodeAuthScopeDuplicate, "x", "4"))) {
t.Fatal("wrapped 210002 should match")
}
if !IsAuthAlreadyGranted(errors.New("fail: code=210013 msg=授权范围重复获取 requestId=x")) {
t.Fatal("legacy string 210013 should match")
}
if IsAuthAlreadyGranted(errors.New("无需重复操作")) {
t.Fatal("msg-only must not match per official docs")
}
}