package alicloud import ( "crypto/md5" "errors" "fmt" "io" "net/http" "net/url" "strings" "time" "tyapi-server/internal/shared/external_logger" ) var ( ErrDatasource = errors.New("数据源异常") ErrSystem = errors.New("系统异常") ) // AlicloudConfig 阿里云配置 type AlicloudConfig struct { Host string AppCode string } // AlicloudService 阿里云服务 type AlicloudService struct { config AlicloudConfig logger *external_logger.ExternalServiceLogger } // NewAlicloudService 创建阿里云服务实例 func NewAlicloudService(host, appCode string, logger ...*external_logger.ExternalServiceLogger) *AlicloudService { var serviceLogger *external_logger.ExternalServiceLogger if len(logger) > 0 { serviceLogger = logger[0] } return &AlicloudService{ config: AlicloudConfig{ Host: host, AppCode: appCode, }, logger: serviceLogger, } } // generateRequestID 生成请求ID func (a *AlicloudService) generateRequestID() string { timestamp := time.Now().UnixNano() hash := md5.Sum([]byte(fmt.Sprintf("%d_%s", timestamp, a.config.Host))) return fmt.Sprintf("alicloud_%x", hash[:8]) } // CallAPI 调用阿里云API的通用方法 // path: API路径(如 "api-mall/api/id_card/check") // params: 请求参数 func (a *AlicloudService) CallAPI(path string, params map[string]interface{}) (respBytes []byte, err error) { startTime := time.Now() requestID := a.generateRequestID() transactionID := "" // 构建请求URL reqURL := a.config.Host + "/" + path // 记录请求日志 if a.logger != nil { a.logger.LogRequest(requestID, transactionID, path, reqURL) } // 构建请求参数 formData := url.Values{} for key, value := range params { formData.Set(key, fmt.Sprintf("%v", value)) } // 创建HTTP请求 req, err := http.NewRequest("POST", reqURL, strings.NewReader(formData.Encode())) if err != nil { if a.logger != nil { a.logger.LogError(requestID, transactionID, path, errors.Join(ErrSystem, err), params) } return nil, fmt.Errorf("%w: %s", ErrSystem, err.Error()) } // 设置请求头 req.Header.Set("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8") req.Header.Set("Authorization", "APPCODE "+a.config.AppCode) // 发送请求,超时时间设置为60秒 client := &http.Client{ Timeout: 60 * time.Second, } resp, err := client.Do(req) if err != nil { // 检查是否是超时错误 isTimeout := false if netErr, ok := err.(interface{ Timeout() bool }); ok && netErr.Timeout() { isTimeout = true } else if errStr := err.Error(); errStr == "context deadline exceeded" || errStr == "timeout" || errStr == "Client.Timeout exceeded" || errStr == "net/http: request canceled" { isTimeout = true } if isTimeout { if a.logger != nil { a.logger.LogError(requestID, transactionID, path, errors.Join(ErrDatasource, fmt.Errorf("API请求超时: %s", err.Error())), params) } return nil, fmt.Errorf("%w: API请求超时: %s", ErrDatasource, err.Error()) } if a.logger != nil { a.logger.LogError(requestID, transactionID, path, errors.Join(ErrSystem, err), params) } return nil, fmt.Errorf("%w: %s", ErrSystem, err.Error()) } defer resp.Body.Close() // 读取响应体 body, err := io.ReadAll(resp.Body) if err != nil { if a.logger != nil { a.logger.LogError(requestID, transactionID, path, errors.Join(ErrSystem, err), params) } return nil, fmt.Errorf("%w: %s", ErrSystem, err.Error()) } // 记录响应日志(不记录具体响应数据) if a.logger != nil { duration := time.Since(startTime) a.logger.LogResponse(requestID, transactionID, path, resp.StatusCode, duration) } // 直接返回原始响应body,让调用方自己处理 return body, nil } // GetConfig 获取配置信息 func (a *AlicloudService) GetConfig() AlicloudConfig { return a.config }