Merge branch 'main' of http://1.117.67.95:3000/team/tyapi-server
This commit is contained in:
@@ -412,11 +412,8 @@ func NewContainer() *Container {
|
|||||||
)
|
)
|
||||||
},
|
},
|
||||||
// AlicloudService - 阿里云服务
|
// AlicloudService - 阿里云服务
|
||||||
func(cfg *config.Config) *alicloud.AlicloudService {
|
func(cfg *config.Config) (*alicloud.AlicloudService, error) {
|
||||||
return alicloud.NewAlicloudService(
|
return alicloud.NewAlicloudServiceWithConfig(cfg)
|
||||||
cfg.Alicloud.Host,
|
|
||||||
cfg.Alicloud.AppCode,
|
|
||||||
)
|
|
||||||
},
|
},
|
||||||
sharedhttp.NewGinRouter,
|
sharedhttp.NewGinRouter,
|
||||||
ipgeo.NewLocator,
|
ipgeo.NewLocator,
|
||||||
|
|||||||
@@ -4,10 +4,11 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"tyapi-server/internal/domains/api/dto"
|
"tyapi-server/internal/domains/api/dto"
|
||||||
"tyapi-server/internal/domains/api/services/processors"
|
"tyapi-server/internal/domains/api/services/processors"
|
||||||
"tyapi-server/internal/infrastructure/external/alicloud"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ProcessYYSYBE08Request YYSYBE08 API处理方法 - 使用数脉二要素验证
|
// ProcessYYSYBE08Request YYSYBE08 API处理方法 - 使用数脉二要素验证
|
||||||
@@ -34,26 +35,16 @@ func ProcessYYSYBE08Request(ctx context.Context, params []byte, deps *processors
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
// 使用实时接口(app_id 和 app_secret)重试
|
// 使用实时接口(app_id 和 app_secret)重试
|
||||||
respBytes, err = deps.ShumaiService.CallAPIForm(ctx, apiPath, reqFormData, false)
|
respBytes, err = deps.ShumaiService.CallAPIForm(ctx, apiPath, reqFormData, false)
|
||||||
// 重试仍失败:阿里云身份证二要素兜底,返回原始 body;兜底仍失败则按阿里云错误类型返回(与 YYSY3M8S 对数脉的分流一致)
|
// 重试仍失败:阿里云身份证二要素兜底,并直接返回统一映射响应
|
||||||
if err != nil {
|
if err != nil {
|
||||||
rawBytes, aerr := callAliyunIDCardCheckRaw(ctx, deps, paramsDto.Name, paramsDto.IDCard)
|
return callAliyunIDCardCheckRaw(ctx, deps, paramsDto.Name, paramsDto.IDCard)
|
||||||
if aerr != nil {
|
|
||||||
if errors.Is(aerr, alicloud.ErrDatasource) {
|
|
||||||
return nil, errors.Join(processors.ErrDatasource, aerr)
|
|
||||||
}
|
|
||||||
if errors.Is(aerr, alicloud.ErrSystem) {
|
|
||||||
return nil, errors.Join(processors.ErrSystem, aerr)
|
|
||||||
}
|
|
||||||
return nil, errors.Join(processors.ErrSystem, aerr)
|
|
||||||
}
|
|
||||||
return rawBytes, nil
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 解析数脉 /v4/id_card/check 的 data 内容(CallAPIForm 返回的即 data 对象)
|
// 解析数脉 /v4/id_card/check 的 data 内容(CallAPIForm 返回的即 data 对象)
|
||||||
// 数卖响应: result 0-一致 1-不一致 2-无记录(预留); desc 如 "一致"/"不一致"
|
// 数卖响应: result 0-一致 1-不一致 2-无记录(预留); desc 如 "一致"/"不一致"
|
||||||
var shumaiData struct {
|
var shumaiData struct {
|
||||||
Result int `json:"result"`
|
Result interface{} `json:"result"`
|
||||||
OrderNo string `json:"order_no"`
|
OrderNo string `json:"order_no"`
|
||||||
Desc string `json:"desc"`
|
Desc string `json:"desc"`
|
||||||
Sex string `json:"sex"`
|
Sex string `json:"sex"`
|
||||||
@@ -79,30 +70,7 @@ func ProcessYYSYBE08Request(ctx context.Context, params []byte, deps *processors
|
|||||||
|
|
||||||
// 按数卖 result 验证结果处理: 0-一致 1-不一致 2-无记录(预留)
|
// 按数卖 result 验证结果处理: 0-一致 1-不一致 2-无记录(预留)
|
||||||
// resultCode: 0XXX=一致, 5XXX=不一致/无记录
|
// resultCode: 0XXX=一致, 5XXX=不一致/无记录
|
||||||
var resultCode, verifyResult, resultMsg string
|
resultCode, verifyResult, resultMsg := mapIDCardCheckResult(shumaiData.Result, shumaiData.Desc)
|
||||||
switch shumaiData.Result {
|
|
||||||
case 0: // 一致(收费)
|
|
||||||
resultCode = "0XXX"
|
|
||||||
verifyResult = "一致"
|
|
||||||
resultMsg = shumaiData.Desc
|
|
||||||
if resultMsg == "" {
|
|
||||||
resultMsg = "成功"
|
|
||||||
}
|
|
||||||
case 1: // 不一致(收费)
|
|
||||||
resultCode = "5XXX"
|
|
||||||
verifyResult = "不一致"
|
|
||||||
resultMsg = shumaiData.Desc
|
|
||||||
if resultMsg == "" {
|
|
||||||
resultMsg = "不一致"
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
resultCode = "5XXX"
|
|
||||||
verifyResult = "不一致"
|
|
||||||
resultMsg = shumaiData.Desc
|
|
||||||
if resultMsg == "" {
|
|
||||||
resultMsg = "不一致"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 构建目标格式的响应
|
// 构建目标格式的响应
|
||||||
response := map[string]interface{}{
|
response := map[string]interface{}{
|
||||||
@@ -119,3 +87,48 @@ func ProcessYYSYBE08Request(ctx context.Context, params []byte, deps *processors
|
|||||||
|
|
||||||
return json.Marshal(response)
|
return json.Marshal(response)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func mapIDCardCheckResult(rawResult interface{}, desc string) (resultCode, verifyResult, resultMsg string) {
|
||||||
|
if isResultZero(rawResult) {
|
||||||
|
resultCode = "0XXX"
|
||||||
|
verifyResult = "一致"
|
||||||
|
resultMsg = desc
|
||||||
|
if resultMsg == "" {
|
||||||
|
resultMsg = "成功"
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
resultCode = "5XXX"
|
||||||
|
verifyResult = "不一致"
|
||||||
|
resultMsg = desc
|
||||||
|
if resultMsg == "" {
|
||||||
|
resultMsg = "不一致"
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func isResultZero(v interface{}) bool {
|
||||||
|
switch r := v.(type) {
|
||||||
|
case float64:
|
||||||
|
return r == 0
|
||||||
|
case int:
|
||||||
|
return r == 0
|
||||||
|
case int32:
|
||||||
|
return r == 0
|
||||||
|
case int64:
|
||||||
|
return r == 0
|
||||||
|
case json.Number:
|
||||||
|
n, err := r.Int64()
|
||||||
|
return err == nil && n == 0
|
||||||
|
case string:
|
||||||
|
s := strings.TrimSpace(r)
|
||||||
|
if s == "" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
n, err := strconv.ParseFloat(s, 64)
|
||||||
|
return err == nil && n == 0
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -7,9 +7,10 @@ import (
|
|||||||
|
|
||||||
"tyapi-server/internal/domains/api/dto"
|
"tyapi-server/internal/domains/api/dto"
|
||||||
"tyapi-server/internal/domains/api/services/processors"
|
"tyapi-server/internal/domains/api/services/processors"
|
||||||
|
"tyapi-server/internal/infrastructure/external/alicloud"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ProcessYYSYBE08testRequest 与 YYSYBE08 相同入参,底层使用阿里云市场身份证二要素校验;响应为阿里云接口原始 body(不做字段映射)
|
// ProcessYYSYBE08testRequest 与 YYSYBE08 相同入参,底层使用阿里云市场身份证二要素校验;响应映射为 ctidRequest.ctidAuth 格式
|
||||||
func ProcessYYSYBE08testRequest(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
|
func ProcessYYSYBE08testRequest(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
|
||||||
var paramsDto dto.YYSYBE08Req
|
var paramsDto dto.YYSYBE08Req
|
||||||
if err := json.Unmarshal(params, ¶msDto); err != nil {
|
if err := json.Unmarshal(params, ¶msDto); err != nil {
|
||||||
@@ -23,12 +24,40 @@ func ProcessYYSYBE08testRequest(ctx context.Context, params []byte, deps *proces
|
|||||||
return callAliyunIDCardCheckRaw(ctx, deps, paramsDto.Name, paramsDto.IDCard)
|
return callAliyunIDCardCheckRaw(ctx, deps, paramsDto.Name, paramsDto.IDCard)
|
||||||
}
|
}
|
||||||
|
|
||||||
// callAliyunIDCardCheckRaw POST api-mall/api/id_card/check(form: name、idcard),返回响应体原文,供 YYSYBE08TEST 与 YYSYBE08 数脉失败兜底共用
|
// callAliyunIDCardCheckRaw POST api-mall/api/id_card/check(form: name、idcard),并映射为 ctidRequest.ctidAuth 响应
|
||||||
func callAliyunIDCardCheckRaw(ctx context.Context, deps *processors.ProcessorDependencies, name, idCard string) ([]byte, error) {
|
func callAliyunIDCardCheckRaw(ctx context.Context, deps *processors.ProcessorDependencies, name, idCard string) ([]byte, error) {
|
||||||
_ = ctx
|
_ = ctx
|
||||||
reqData := map[string]interface{}{
|
reqData := map[string]interface{}{
|
||||||
"name": name,
|
"name": name,
|
||||||
"idcard": idCard,
|
"idcard": idCard,
|
||||||
}
|
}
|
||||||
return deps.AlicloudService.CallAPI("api-mall/api/id_card/check", reqData)
|
respBytes, err := deps.AlicloudService.CallAPI("api-mall/api/id_card/check", reqData)
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, alicloud.ErrDatasource) {
|
||||||
|
return nil, errors.Join(processors.ErrDatasource, err)
|
||||||
|
}
|
||||||
|
return nil, errors.Join(processors.ErrSystem, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var aliyunData struct {
|
||||||
|
Result interface{} `json:"result"`
|
||||||
|
Desc string `json:"desc"`
|
||||||
|
}
|
||||||
|
if err := json.Unmarshal(respBytes, &aliyunData); err != nil {
|
||||||
|
return nil, errors.Join(processors.ErrSystem, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
resultCode, verifyResult, resultMsg := mapIDCardCheckResult(aliyunData.Result, aliyunData.Desc)
|
||||||
|
response := map[string]interface{}{
|
||||||
|
"ctidRequest": map[string]interface{}{
|
||||||
|
"ctidAuth": map[string]interface{}{
|
||||||
|
"idCard": idCard,
|
||||||
|
"name": name,
|
||||||
|
"resultCode": resultCode,
|
||||||
|
"resultMsg": resultMsg,
|
||||||
|
"verifyResult": verifyResult,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return json.Marshal(response)
|
||||||
}
|
}
|
||||||
|
|||||||
49
internal/infrastructure/external/alicloud/alicloud_factory.go
vendored
Normal file
49
internal/infrastructure/external/alicloud/alicloud_factory.go
vendored
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
package alicloud
|
||||||
|
|
||||||
|
import (
|
||||||
|
"tyapi-server/internal/config"
|
||||||
|
"tyapi-server/internal/shared/external_logger"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewAlicloudServiceWithConfig 使用配置创建阿里云服务,并启用外部服务调用日志
|
||||||
|
func NewAlicloudServiceWithConfig(cfg *config.Config) (*AlicloudService, error) {
|
||||||
|
loggingConfig := external_logger.ExternalServiceLoggingConfig{
|
||||||
|
Enabled: true,
|
||||||
|
LogDir: "./logs/external_services",
|
||||||
|
ServiceName: "alicloud",
|
||||||
|
UseDaily: false,
|
||||||
|
EnableLevelSeparation: true,
|
||||||
|
LevelConfigs: map[string]external_logger.ExternalServiceLevelFileConfig{
|
||||||
|
"info": {
|
||||||
|
MaxSize: 100,
|
||||||
|
MaxBackups: 3,
|
||||||
|
MaxAge: 28,
|
||||||
|
Compress: true,
|
||||||
|
},
|
||||||
|
"error": {
|
||||||
|
MaxSize: 100,
|
||||||
|
MaxBackups: 3,
|
||||||
|
MaxAge: 28,
|
||||||
|
Compress: true,
|
||||||
|
},
|
||||||
|
"warn": {
|
||||||
|
MaxSize: 100,
|
||||||
|
MaxBackups: 3,
|
||||||
|
MaxAge: 28,
|
||||||
|
Compress: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
logger, err := external_logger.NewExternalServiceLogger(loggingConfig)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return NewAlicloudService(
|
||||||
|
cfg.Alicloud.Host,
|
||||||
|
cfg.Alicloud.AppCode,
|
||||||
|
logger,
|
||||||
|
), nil
|
||||||
|
}
|
||||||
|
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
package alicloud
|
package alicloud
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/md5"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
@@ -8,6 +9,8 @@ import (
|
|||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"tyapi-server/internal/shared/external_logger"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -24,25 +27,47 @@ type AlicloudConfig struct {
|
|||||||
// AlicloudService 阿里云服务
|
// AlicloudService 阿里云服务
|
||||||
type AlicloudService struct {
|
type AlicloudService struct {
|
||||||
config AlicloudConfig
|
config AlicloudConfig
|
||||||
|
logger *external_logger.ExternalServiceLogger
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewAlicloudService 创建阿里云服务实例
|
// NewAlicloudService 创建阿里云服务实例
|
||||||
func NewAlicloudService(host, appCode string) *AlicloudService {
|
func NewAlicloudService(host, appCode string, logger ...*external_logger.ExternalServiceLogger) *AlicloudService {
|
||||||
|
var serviceLogger *external_logger.ExternalServiceLogger
|
||||||
|
if len(logger) > 0 {
|
||||||
|
serviceLogger = logger[0]
|
||||||
|
}
|
||||||
return &AlicloudService{
|
return &AlicloudService{
|
||||||
config: AlicloudConfig{
|
config: AlicloudConfig{
|
||||||
Host: host,
|
Host: host,
|
||||||
AppCode: appCode,
|
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的通用方法
|
// CallAPI 调用阿里云API的通用方法
|
||||||
// path: API路径(如 "api-mall/api/id_card/check")
|
// path: API路径(如 "api-mall/api/id_card/check")
|
||||||
// params: 请求参数
|
// params: 请求参数
|
||||||
func (a *AlicloudService) CallAPI(path string, params map[string]interface{}) (respBytes []byte, err error) {
|
func (a *AlicloudService) CallAPI(path string, params map[string]interface{}) (respBytes []byte, err error) {
|
||||||
|
startTime := time.Now()
|
||||||
|
requestID := a.generateRequestID()
|
||||||
|
transactionID := ""
|
||||||
|
|
||||||
// 构建请求URL
|
// 构建请求URL
|
||||||
reqURL := a.config.Host + "/" + path
|
reqURL := a.config.Host + "/" + path
|
||||||
|
|
||||||
|
// 记录请求日志
|
||||||
|
if a.logger != nil {
|
||||||
|
a.logger.LogRequest(requestID, transactionID, path, reqURL)
|
||||||
|
}
|
||||||
|
|
||||||
// 构建请求参数
|
// 构建请求参数
|
||||||
formData := url.Values{}
|
formData := url.Values{}
|
||||||
for key, value := range params {
|
for key, value := range params {
|
||||||
@@ -52,6 +77,9 @@ func (a *AlicloudService) CallAPI(path string, params map[string]interface{}) (r
|
|||||||
// 创建HTTP请求
|
// 创建HTTP请求
|
||||||
req, err := http.NewRequest("POST", reqURL, strings.NewReader(formData.Encode()))
|
req, err := http.NewRequest("POST", reqURL, strings.NewReader(formData.Encode()))
|
||||||
if err != nil {
|
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())
|
return nil, fmt.Errorf("%w: %s", ErrSystem, err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -69,8 +97,7 @@ func (a *AlicloudService) CallAPI(path string, params map[string]interface{}) (r
|
|||||||
isTimeout := false
|
isTimeout := false
|
||||||
if netErr, ok := err.(interface{ Timeout() bool }); ok && netErr.Timeout() {
|
if netErr, ok := err.(interface{ Timeout() bool }); ok && netErr.Timeout() {
|
||||||
isTimeout = true
|
isTimeout = true
|
||||||
} else if errStr := err.Error();
|
} else if errStr := err.Error(); errStr == "context deadline exceeded" ||
|
||||||
errStr == "context deadline exceeded" ||
|
|
||||||
errStr == "timeout" ||
|
errStr == "timeout" ||
|
||||||
errStr == "Client.Timeout exceeded" ||
|
errStr == "Client.Timeout exceeded" ||
|
||||||
errStr == "net/http: request canceled" {
|
errStr == "net/http: request canceled" {
|
||||||
@@ -78,8 +105,14 @@ func (a *AlicloudService) CallAPI(path string, params map[string]interface{}) (r
|
|||||||
}
|
}
|
||||||
|
|
||||||
if isTimeout {
|
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())
|
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())
|
return nil, fmt.Errorf("%w: %s", ErrSystem, err.Error())
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
@@ -87,9 +120,18 @@ func (a *AlicloudService) CallAPI(path string, params map[string]interface{}) (r
|
|||||||
// 读取响应体
|
// 读取响应体
|
||||||
body, err := io.ReadAll(resp.Body)
|
body, err := io.ReadAll(resp.Body)
|
||||||
if err != nil {
|
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())
|
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,让调用方自己处理
|
// 直接返回原始响应body,让调用方自己处理
|
||||||
return body, nil
|
return body, nil
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user