This commit is contained in:
2026-07-24 10:19:32 +08:00
parent 3bf04be347
commit 61f95aeedb

View File

@@ -45,8 +45,8 @@ type RongxingService struct {
logger *external_logger.ExternalServiceLogger logger *external_logger.ExternalServiceLogger
client *http.Client client *http.Client
tokenMu sync.RWMutex // loginMu 避免并发登录打爆对方;不缓存 token每次业务调用重新登录。
cachedToken string loginMu sync.Mutex
} }
// apiResponse 戎行统一响应。code 可能是数字或字符串;扣费以 consumeFlag 为准。 // apiResponse 戎行统一响应。code 可能是数字或字符串;扣费以 consumeFlag 为准。
@@ -126,7 +126,7 @@ func (s *RongxingService) GetConfig() serviceConfig {
// CallAPI 通用业务接口调用。 // CallAPI 通用业务接口调用。
// apiPath 为相对路径(如 /third/loan/info360reqData 为已组装好的请求体。 // apiPath 为相对路径(如 /third/loan/info360reqData 为已组装好的请求体。
// Token 获取与 Header 注入由服务内部处理401/403 时自动刷新 Token 并重试一次。 // 每次调用重新登录取 Token不本地缓存若业务码/HTTP 仍为 401/403再登录重试一次。
func (s *RongxingService) CallAPI(ctx context.Context, apiPath string, reqData map[string]interface{}) ([]byte, error) { func (s *RongxingService) CallAPI(ctx context.Context, apiPath string, reqData map[string]interface{}) ([]byte, error) {
apiKey := strings.Trim(apiPath, "/") apiKey := strings.Trim(apiPath, "/")
@@ -185,7 +185,6 @@ func (s *RongxingService) CallAPI(ctx context.Context, apiPath string, reqData m
respStr := string(respBody) respStr := string(respBody)
if statusCode == http.StatusUnauthorized || statusCode == http.StatusForbidden { if statusCode == http.StatusUnauthorized || statusCode == http.StatusForbidden {
s.clearToken()
if attempt == 0 { if attempt == 0 {
continue continue
} }
@@ -208,6 +207,11 @@ func (s *RongxingService) CallAPI(ctx context.Context, apiPath string, reqData m
} }
code := resp.code() code := resp.code()
// 对方常以 HTTP 200 + body.code=401 表示 token 无效(非 HTTP 401
if isTokenInvalidCode(code) && attempt == 0 {
continue
}
payload := extractBusinessPayload(resp.Data) payload := extractBusinessPayload(resp.Data)
// 扣费只看 consumeFlag1 扣费按成功返回0 不扣费 // 扣费只看 consumeFlag1 扣费按成功返回0 不扣费
@@ -226,32 +230,20 @@ func (s *RongxingService) CallAPI(ctx context.Context, apiPath string, reqData m
return nil, errors.Join(ErrDatasource, errors.New("请求失败")) return nil, errors.Join(ErrDatasource, errors.New("请求失败"))
} }
// getToken 每次重新登录,不缓存 token。
func (s *RongxingService) getToken(ctx context.Context, transactionID string) (string, error) { func (s *RongxingService) getToken(ctx context.Context, transactionID string) (string, error) {
s.tokenMu.RLock() s.loginMu.Lock()
token := s.cachedToken defer s.loginMu.Unlock()
s.tokenMu.RUnlock() return s.login(ctx, transactionID)
if token != "" {
return token, nil
} }
s.tokenMu.Lock() func isTokenInvalidCode(code string) bool {
defer s.tokenMu.Unlock() switch strings.TrimSpace(code) {
if s.cachedToken != "" { case "401", "403":
return s.cachedToken, nil return true
default:
return false
} }
token, err := s.login(ctx, transactionID)
if err != nil {
return "", err
}
s.cachedToken = token
return token, nil
}
func (s *RongxingService) clearToken() {
s.tokenMu.Lock()
s.cachedToken = ""
s.tokenMu.Unlock()
} }
func (s *RongxingService) login(ctx context.Context, transactionID string) (string, error) { func (s *RongxingService) login(ctx context.Context, transactionID string) (string, error) {
@@ -407,7 +399,8 @@ func classifyTransportError(err error) string {
if errors.As(err, &netErr) && netErr.Timeout() { if errors.As(err, &netErr) && netErr.Timeout() {
return "网络超时" return "网络超时"
} }
return "其他网络错误(详见 cause)" // 完整原始错误在同一条日志的 error/cause 字段中,不在别的文件
return "其他网络错误(见本条日志 error 全文)"
} }
func (s *RongxingService) validateConfig() error { func (s *RongxingService) validateConfig() error {