diff --git a/internal/infrastructure/external/nuoer/nuoer_service.go b/internal/infrastructure/external/nuoer/nuoer_service.go index 3ae60cb..42f68fa 100644 --- a/internal/infrastructure/external/nuoer/nuoer_service.go +++ b/internal/infrastructure/external/nuoer/nuoer_service.go @@ -3,7 +3,6 @@ package nuoer import ( "bytes" "context" - "crypto/md5" "encoding/json" "errors" "fmt" @@ -17,6 +16,26 @@ import ( const defaultRequestTimeout = 4 * time.Second +// queryBillingAPIKeys 查询计费接口:数据未查得(busiCode=1000)仍按成功计费,返回空数据 +var queryBillingAPIKeys = map[string]struct{}{ + "idRiskTagV106": {}, // 身份风险V106 + "personalLawsuit_cv2": {}, // 企业诉讼定制版 + "personalLawsuit_cv1": {}, // 个人诉讼定制版 + "loanRiskTagV11": {}, // 借贷意向查询 + "loanRiskTagV5": {}, // 风险变量V5 + "loanRiskTagV12": {}, // 特殊名单 + "blackListV121_3_1": {}, // 债务逾期黑名单V3_1 + "blackListV110": {}, // 特殊名单V110 + "zhiTongModelG": {}, // 智瞳-通用版 + "zhitong_ultra_v4_score": {}, // 智瞳分尊享版 + "zhixiangScore": {}, // 智享分 +} + +func isQueryBillingAPIKey(apiKey string) bool { + _, ok := queryBillingAPIKeys[apiKey] + return ok +} + // nuoerResponse 诺尔智汇通用响应 type nuoerResponse struct { Code int `json:"code"` @@ -55,10 +74,18 @@ func NewNuoerService(url, appID, appSecret string, timeout time.Duration, logger } } -func (s *NuoerService) generateRequestID() string { - timestamp := time.Now().UnixNano() - hash := md5.Sum([]byte(fmt.Sprintf("%d_%s", timestamp, s.config.AppID))) - return fmt.Sprintf("nuoer_%x", hash[:8]) +func (s *NuoerService) logResponse(transactionID, apiKey string, statusCode int, duration time.Duration, seqNo string) { + if s.logger == nil { + return + } + s.logger.LogResponse(seqNo, transactionID, apiKey, statusCode, duration) +} + +func (s *NuoerService) logError(transactionID, apiKey, seqNo string, err error, payload interface{}) { + if s.logger == nil { + return + } + s.logger.LogError(seqNo, transactionID, apiKey, err, payload) } func (s *NuoerService) CallAPI(ctx context.Context, apiKey, apiPath string, body map[string]string) (*nuoerResponse, error) { @@ -70,7 +97,6 @@ func (s *NuoerService) CallAPI(ctx context.Context, apiKey, apiPath string, body requestURL += apiPath } - requestID := s.generateRequestID() startTime := time.Now() var transactionID string @@ -89,24 +115,20 @@ func (s *NuoerService) CallAPI(ctx context.Context, apiKey, apiPath string, body } if s.logger != nil { - s.logger.LogRequest(requestID, transactionID, apiKey, requestURL) + s.logger.LogRequest("", transactionID, apiKey, requestURL) } bodyBytes, err := json.Marshal(requestPayload) if err != nil { err = errors.Join(ErrSystem, err) - if s.logger != nil { - s.logger.LogError(requestID, transactionID, apiKey, err, requestPayload) - } + s.logError(transactionID, apiKey, "", err, requestPayload) return nil, err } req, err := http.NewRequestWithContext(ctx, http.MethodPost, requestURL, bytes.NewBuffer(bodyBytes)) if err != nil { err = errors.Join(ErrSystem, err) - if s.logger != nil { - s.logger.LogError(requestID, transactionID, apiKey, err, requestPayload) - } + s.logError(transactionID, apiKey, "", err, requestPayload) return nil, err } req.Header.Set("Content-Type", "application/json") @@ -115,9 +137,7 @@ func (s *NuoerService) CallAPI(ctx context.Context, apiKey, apiPath string, body resp, err := client.Do(req) if err != nil { err = wrapHTTPError(err) - if s.logger != nil { - s.logger.LogError(requestID, transactionID, apiKey, err, requestPayload) - } + s.logError(transactionID, apiKey, "", err, requestPayload) return nil, err } defer resp.Body.Close() @@ -125,78 +145,72 @@ func (s *NuoerService) CallAPI(ctx context.Context, apiKey, apiPath string, body respBody, err := io.ReadAll(resp.Body) if err != nil { err = errors.Join(ErrSystem, err) - if s.logger != nil { - s.logger.LogError(requestID, transactionID, apiKey, err, requestPayload) - } + s.logError(transactionID, apiKey, "", err, requestPayload) return nil, err } - if s.logger != nil { - s.logger.LogResponse(requestID, transactionID, apiKey, resp.StatusCode, time.Since(startTime)) - } + duration := time.Since(startTime) if resp.StatusCode != http.StatusOK { err = errors.Join(ErrDatasource, fmt.Errorf("HTTP状态码 %d", resp.StatusCode)) - if s.logger != nil { - s.logger.LogError(requestID, transactionID, apiKey, err, requestPayload) - } + s.logError(transactionID, apiKey, "", err, requestPayload) return nil, err } var nuoerResp nuoerResponse if err := json.Unmarshal(respBody, &nuoerResp); err != nil { err = errors.Join(ErrSystem, fmt.Errorf("响应解析失败: %w", err)) - if s.logger != nil { - s.logger.LogError(requestID, transactionID, apiKey, err, requestPayload) - } + s.logError(transactionID, apiKey, "", err, requestPayload) return nil, err } if nuoerResp.Code != CodeSuccess { + if nuoerResp.Code == BusiCodeNotFound && isQueryBillingAPIKey(apiKey) { + nuoerResp.Data = map[string]interface{}{} + s.logResponse(transactionID, apiKey, resp.StatusCode, duration, nuoerResp.SeqNo) + return &nuoerResp, nil + } nuoerErr := NewNuoerError(nuoerResp.Code, nuoerResp.Msg) err = errors.Join(GetErrByPlatformCode(nuoerResp.Code), nuoerErr) - if s.logger != nil { - s.logger.LogErrorWithResponseID(requestID, transactionID, apiKey, nuoerErr, requestPayload, nuoerResp.SeqNo) - } + s.logError(transactionID, apiKey, nuoerResp.SeqNo, nuoerErr, requestPayload) return nil, err } if nuoerResp.Data == nil { err = errors.Join(ErrSystem, errors.New("响应 data 为空")) - if s.logger != nil { - s.logger.LogErrorWithResponseID(requestID, transactionID, apiKey, err, requestPayload, nuoerResp.SeqNo) - } + s.logError(transactionID, apiKey, nuoerResp.SeqNo, err, requestPayload) return nil, err } busiCode, busiMsg, ok := parseDataBusiInfo(nuoerResp.Data) if !ok { err = errors.Join(ErrSystem, errors.New("响应 data 无法解析 busiCode")) - if s.logger != nil { - s.logger.LogErrorWithResponseID(requestID, transactionID, apiKey, err, requestPayload, nuoerResp.SeqNo) - } + s.logError(transactionID, apiKey, nuoerResp.SeqNo, err, requestPayload) return nil, err } if busiCode != BusiCodeSuccess { + if busiCode == BusiCodeNotFound && isQueryBillingAPIKey(apiKey) { + nuoerResp.Data = map[string]interface{}{} + s.logResponse(transactionID, apiKey, resp.StatusCode, duration, nuoerResp.SeqNo) + return &nuoerResp, nil + } busiErr := NewNuoerBusiError(busiCode, busiMsg) err = errors.Join(GetErrByBusiCode(busiCode), busiErr) - if s.logger != nil { - s.logger.LogErrorWithResponseID(requestID, transactionID, apiKey, busiErr, requestPayload, nuoerResp.SeqNo) - } + s.logError(transactionID, apiKey, nuoerResp.SeqNo, busiErr, requestPayload) return nil, err } cleanedData, err := stripBusiMetaFromData(nuoerResp.Data) if err != nil { err = errors.Join(ErrSystem, fmt.Errorf("响应 data 清理失败: %w", err)) - if s.logger != nil { - s.logger.LogErrorWithResponseID(requestID, transactionID, apiKey, err, requestPayload, nuoerResp.SeqNo) - } + s.logError(transactionID, apiKey, nuoerResp.SeqNo, err, requestPayload) return nil, err } nuoerResp.Data = cleanedData + s.logResponse(transactionID, apiKey, resp.StatusCode, duration, nuoerResp.SeqNo) + return &nuoerResp, nil }