new
This commit is contained in:
44
config.yaml
44
config.yaml
@@ -53,7 +53,6 @@ logger:
|
|||||||
log_dir: "logs" # 日志目录
|
log_dir: "logs" # 日志目录
|
||||||
use_daily: true # 是否按日分包
|
use_daily: true # 是否按日分包
|
||||||
use_color: false # 是否使用彩色输出(仅console格式有效)
|
use_color: false # 是否使用彩色输出(仅console格式有效)
|
||||||
|
|
||||||
# 文件配置
|
# 文件配置
|
||||||
max_size: 100 # 单个文件最大大小(MB)
|
max_size: 100 # 单个文件最大大小(MB)
|
||||||
max_backups: 5 # 最大备份文件数
|
max_backups: 5 # 最大备份文件数
|
||||||
@@ -125,7 +124,7 @@ sms:
|
|||||||
access_key_id: "LTAI5tKGB3TVJbMHSoZN3yr9"
|
access_key_id: "LTAI5tKGB3TVJbMHSoZN3yr9"
|
||||||
access_key_secret: "OCQ30GWp4yENMjmfOAaagksE18bp65"
|
access_key_secret: "OCQ30GWp4yENMjmfOAaagksE18bp65"
|
||||||
endpoint_url: "dysmsapi.aliyuncs.com"
|
endpoint_url: "dysmsapi.aliyuncs.com"
|
||||||
sign_name: "天远查"
|
sign_name: "天远数据"
|
||||||
template_code: "SMS_474525324"
|
template_code: "SMS_474525324"
|
||||||
code_length: 6
|
code_length: 6
|
||||||
expire_time: 5m
|
expire_time: 5m
|
||||||
@@ -236,6 +235,7 @@ development:
|
|||||||
wechat_work:
|
wechat_work:
|
||||||
webhook_url: ""
|
webhook_url: ""
|
||||||
secret: ""
|
secret: ""
|
||||||
|
|
||||||
# ===========================================
|
# ===========================================
|
||||||
# 📝 e签宝服务配置
|
# 📝 e签宝服务配置
|
||||||
# ===========================================
|
# ===========================================
|
||||||
@@ -278,9 +278,9 @@ wallet:
|
|||||||
|
|
||||||
# 余额预警配置
|
# 余额预警配置
|
||||||
balance_alert:
|
balance_alert:
|
||||||
default_enabled: true # 默认启用余额预警
|
default_enabled: true # 默认启用余额预警
|
||||||
default_threshold: 200.00 # 默认预警阈值
|
default_threshold: 200.00 # 默认预警阈值
|
||||||
alert_cooldown_hours: 24 # 预警冷却时间(小时)
|
alert_cooldown_hours: 24 # 预警冷却时间(小时)
|
||||||
|
|
||||||
# ===========================================
|
# ===========================================
|
||||||
# 🌍 西部数据配置
|
# 🌍 西部数据配置
|
||||||
@@ -410,3 +410,37 @@ zhicha:
|
|||||||
max_backups: 5
|
max_backups: 5
|
||||||
max_age: 30
|
max_age: 30
|
||||||
compress: true
|
compress: true
|
||||||
|
|
||||||
|
# ===========================================
|
||||||
|
# 🎯 行为数据配置
|
||||||
|
# ===========================================
|
||||||
|
xingwei:
|
||||||
|
url: "https://sjztyh.chengdaoji.cn/dataCenterManageApi/manage/interface/doc/api/handle"
|
||||||
|
api_id: "jGtqla2FQv1zuXuH"
|
||||||
|
api_key: "iR1qS9725N4JA70gwlwohqT3ogl2zBf3"
|
||||||
|
|
||||||
|
# 行为数据日志配置
|
||||||
|
logging:
|
||||||
|
enabled: true
|
||||||
|
log_dir: "logs/external_services"
|
||||||
|
service_name: "xingwei"
|
||||||
|
use_daily: true
|
||||||
|
enable_level_separation: true
|
||||||
|
|
||||||
|
# 各级别配置
|
||||||
|
level_configs:
|
||||||
|
info:
|
||||||
|
max_size: 100
|
||||||
|
max_backups: 5
|
||||||
|
max_age: 30
|
||||||
|
compress: true
|
||||||
|
error:
|
||||||
|
max_size: 200
|
||||||
|
max_backups: 10
|
||||||
|
max_age: 90
|
||||||
|
compress: true
|
||||||
|
warn:
|
||||||
|
max_size: 100
|
||||||
|
max_backups: 5
|
||||||
|
max_age: 30
|
||||||
|
compress: true
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ type Config struct {
|
|||||||
Yushan YushanConfig `mapstructure:"yushan"`
|
Yushan YushanConfig `mapstructure:"yushan"`
|
||||||
TianYanCha TianYanChaConfig `mapstructure:"tianyancha"`
|
TianYanCha TianYanChaConfig `mapstructure:"tianyancha"`
|
||||||
Alicloud AlicloudConfig `mapstructure:"alicloud"`
|
Alicloud AlicloudConfig `mapstructure:"alicloud"`
|
||||||
|
Xingwei XingweiConfig `mapstructure:"xingwei"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ServerConfig HTTP服务器配置
|
// ServerConfig HTTP服务器配置
|
||||||
@@ -438,6 +439,33 @@ type AlicloudConfig struct {
|
|||||||
AppCode string `mapstructure:"app_code"`
|
AppCode string `mapstructure:"app_code"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// XingweiConfig 行为数据配置
|
||||||
|
type XingweiConfig struct {
|
||||||
|
URL string `mapstructure:"url"`
|
||||||
|
ApiID string `mapstructure:"api_id"`
|
||||||
|
ApiKey string `mapstructure:"api_key"`
|
||||||
|
|
||||||
|
// 行为数据日志配置
|
||||||
|
Logging XingweiLoggingConfig `mapstructure:"logging"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// XingweiLoggingConfig 行为数据日志配置
|
||||||
|
type XingweiLoggingConfig struct {
|
||||||
|
Enabled bool `mapstructure:"enabled"`
|
||||||
|
LogDir string `mapstructure:"log_dir"`
|
||||||
|
UseDaily bool `mapstructure:"use_daily"`
|
||||||
|
EnableLevelSeparation bool `mapstructure:"enable_level_separation"`
|
||||||
|
LevelConfigs map[string]XingweiLevelFileConfig `mapstructure:"level_configs"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// XingweiLevelFileConfig 行为数据级别文件配置
|
||||||
|
type XingweiLevelFileConfig struct {
|
||||||
|
MaxSize int `mapstructure:"max_size"`
|
||||||
|
MaxBackups int `mapstructure:"max_backups"`
|
||||||
|
MaxAge int `mapstructure:"max_age"`
|
||||||
|
Compress bool `mapstructure:"compress"`
|
||||||
|
}
|
||||||
|
|
||||||
// DomainConfig 域名配置
|
// DomainConfig 域名配置
|
||||||
type DomainConfig struct {
|
type DomainConfig struct {
|
||||||
API string `mapstructure:"api"` // API域名
|
API string `mapstructure:"api"` // API域名
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ import (
|
|||||||
"tyapi-server/internal/infrastructure/external/storage"
|
"tyapi-server/internal/infrastructure/external/storage"
|
||||||
"tyapi-server/internal/infrastructure/external/tianyancha"
|
"tyapi-server/internal/infrastructure/external/tianyancha"
|
||||||
"tyapi-server/internal/infrastructure/external/westdex"
|
"tyapi-server/internal/infrastructure/external/westdex"
|
||||||
|
"tyapi-server/internal/infrastructure/external/xingwei"
|
||||||
"tyapi-server/internal/infrastructure/external/yushan"
|
"tyapi-server/internal/infrastructure/external/yushan"
|
||||||
"tyapi-server/internal/infrastructure/external/zhicha"
|
"tyapi-server/internal/infrastructure/external/zhicha"
|
||||||
"tyapi-server/internal/infrastructure/http/handlers"
|
"tyapi-server/internal/infrastructure/http/handlers"
|
||||||
@@ -342,6 +343,10 @@ func NewContainer() *Container {
|
|||||||
func(cfg *config.Config) (*zhicha.ZhichaService, error) {
|
func(cfg *config.Config) (*zhicha.ZhichaService, error) {
|
||||||
return zhicha.NewZhichaServiceWithConfig(cfg)
|
return zhicha.NewZhichaServiceWithConfig(cfg)
|
||||||
},
|
},
|
||||||
|
// XingweiService - 行为数据服务
|
||||||
|
func(cfg *config.Config) (*xingwei.XingweiService, error) {
|
||||||
|
return xingwei.NewXingweiServiceWithConfig(cfg)
|
||||||
|
},
|
||||||
func(cfg *config.Config) *yushan.YushanService {
|
func(cfg *config.Config) *yushan.YushanService {
|
||||||
return yushan.NewYushanService(
|
return yushan.NewYushanService(
|
||||||
cfg.Yushan.URL,
|
cfg.Yushan.URL,
|
||||||
|
|||||||
@@ -68,6 +68,10 @@ type IVYZ5733Req struct {
|
|||||||
Name string `json:"name" validate:"required,min=1,validName"`
|
Name string `json:"name" validate:"required,min=1,validName"`
|
||||||
IDCard string `json:"id_card" validate:"required,validIDCard"`
|
IDCard string `json:"id_card" validate:"required,validIDCard"`
|
||||||
}
|
}
|
||||||
|
type IVYZ81NCReq struct {
|
||||||
|
Name string `json:"name" validate:"required,min=1,validName"`
|
||||||
|
IDCard string `json:"id_card" validate:"required,validIDCard"`
|
||||||
|
}
|
||||||
type IVYZ9363Req struct {
|
type IVYZ9363Req struct {
|
||||||
ManName string `json:"man_name" validate:"required,min=1,validName"`
|
ManName string `json:"man_name" validate:"required,min=1,validName"`
|
||||||
ManIDCard string `json:"man_id_card" validate:"required,validIDCard"`
|
ManIDCard string `json:"man_id_card" validate:"required,validIDCard"`
|
||||||
@@ -277,6 +281,24 @@ type IVYZ7F3AReq struct {
|
|||||||
Authorized string `json:"authorized" validate:"required,oneof=0 1"`
|
Authorized string `json:"authorized" validate:"required,oneof=0 1"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type IVYZ3A7FReq struct {
|
||||||
|
Name string `json:"name" validate:"required,min=1,validName"`
|
||||||
|
IDCard string `json:"id_card" validate:"required,validIDCard"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type IVYZ9D2EReq struct {
|
||||||
|
Name string `json:"name" validate:"required,min=1,validName"`
|
||||||
|
IDCard string `json:"id_card" validate:"required,validIDCard"`
|
||||||
|
UseScenario string `json:"use_scenario" validate:"required,oneof=1 2 3 4 99"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// DWBG7F3AReq 行为数据查询请求参数
|
||||||
|
type DWBG7F3AReq struct {
|
||||||
|
Name string `json:"name" validate:"required,min=1,validName"`
|
||||||
|
IDCard string `json:"id_card" validate:"required,validIDCard"`
|
||||||
|
MobileNo string `json:"mobile_no" validate:"required,min=11,max=11,validMobileNo"`
|
||||||
|
}
|
||||||
|
|
||||||
// 新增的QYGL处理器DTO
|
// 新增的QYGL处理器DTO
|
||||||
type QYGL5A3CReq struct {
|
type QYGL5A3CReq struct {
|
||||||
EntCode string `json:"ent_code" validate:"required,validUSCI"`
|
EntCode string `json:"ent_code" validate:"required,validUSCI"`
|
||||||
@@ -355,9 +377,13 @@ type JRZQ3C7BReq struct {
|
|||||||
|
|
||||||
type JRZQ8A2DReq struct {
|
type JRZQ8A2DReq struct {
|
||||||
MobileNo string `json:"mobile_no" validate:"required,min=11,max=11,validMobileNo"`
|
MobileNo string `json:"mobile_no" validate:"required,min=11,max=11,validMobileNo"`
|
||||||
IDCard string `json:"id_card" validate:"required,validIDCard"`
|
}
|
||||||
|
|
||||||
|
// YYSY8F3AReq 行为数据查询请求参数
|
||||||
|
type YYSY8F3AReq struct {
|
||||||
Name string `json:"name" validate:"required,min=1,validName"`
|
Name string `json:"name" validate:"required,min=1,validName"`
|
||||||
Authorized string `json:"authorized" validate:"required,oneof=0 1"`
|
IDCard string `json:"id_card" validate:"required,validIDCard"`
|
||||||
|
MobileNo string `json:"mobile_no" validate:"required,min=11,max=11,validMobileNo"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type JRZQ5E9FReq struct {
|
type JRZQ5E9FReq struct {
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import (
|
|||||||
"tyapi-server/internal/infrastructure/external/alicloud"
|
"tyapi-server/internal/infrastructure/external/alicloud"
|
||||||
"tyapi-server/internal/infrastructure/external/tianyancha"
|
"tyapi-server/internal/infrastructure/external/tianyancha"
|
||||||
"tyapi-server/internal/infrastructure/external/westdex"
|
"tyapi-server/internal/infrastructure/external/westdex"
|
||||||
|
"tyapi-server/internal/infrastructure/external/xingwei"
|
||||||
"tyapi-server/internal/infrastructure/external/yushan"
|
"tyapi-server/internal/infrastructure/external/yushan"
|
||||||
"tyapi-server/internal/infrastructure/external/zhicha"
|
"tyapi-server/internal/infrastructure/external/zhicha"
|
||||||
"tyapi-server/internal/shared/interfaces"
|
"tyapi-server/internal/shared/interfaces"
|
||||||
@@ -49,6 +50,7 @@ func NewApiRequestService(
|
|||||||
tianYanChaService *tianyancha.TianYanChaService,
|
tianYanChaService *tianyancha.TianYanChaService,
|
||||||
alicloudService *alicloud.AlicloudService,
|
alicloudService *alicloud.AlicloudService,
|
||||||
zhichaService *zhicha.ZhichaService,
|
zhichaService *zhicha.ZhichaService,
|
||||||
|
xingweiService *xingwei.XingweiService,
|
||||||
validator interfaces.RequestValidator,
|
validator interfaces.RequestValidator,
|
||||||
productManagementService *services.ProductManagementService,
|
productManagementService *services.ProductManagementService,
|
||||||
) *ApiRequestService {
|
) *ApiRequestService {
|
||||||
@@ -56,7 +58,7 @@ func NewApiRequestService(
|
|||||||
combService := comb.NewCombService(productManagementService)
|
combService := comb.NewCombService(productManagementService)
|
||||||
|
|
||||||
// 创建处理器依赖容器
|
// 创建处理器依赖容器
|
||||||
processorDeps := processors.NewProcessorDependencies(westDexService, yushanService, tianYanChaService, alicloudService, zhichaService, validator, combService)
|
processorDeps := processors.NewProcessorDependencies(westDexService, yushanService, tianYanChaService, alicloudService, zhichaService, xingweiService, validator, combService)
|
||||||
|
|
||||||
// 统一注册所有处理器
|
// 统一注册所有处理器
|
||||||
registerAllProcessors(combService)
|
registerAllProcessors(combService)
|
||||||
@@ -141,7 +143,8 @@ func registerAllProcessors(combService *comb.CombService) {
|
|||||||
"YYSY8B1C": yysy.ProcessYYSY8B1CRequest,
|
"YYSY8B1C": yysy.ProcessYYSY8B1CRequest,
|
||||||
"YYSY6D9A": yysy.ProcessYYSY6D9ARequest,
|
"YYSY6D9A": yysy.ProcessYYSY6D9ARequest,
|
||||||
"YYSY3E7F": yysy.ProcessYYSY3E7FRequest,
|
"YYSY3E7F": yysy.ProcessYYSY3E7FRequest,
|
||||||
|
"YYSY8F3A": yysy.ProcessYYSY8F3ARequest,
|
||||||
|
|
||||||
// IVYZ系列处理器
|
// IVYZ系列处理器
|
||||||
"IVYZ0B03": ivyz.ProcessIVYZ0B03Request,
|
"IVYZ0B03": ivyz.ProcessIVYZ0B03Request,
|
||||||
"IVYZ2125": ivyz.ProcessIVYZ2125Request,
|
"IVYZ2125": ivyz.ProcessIVYZ2125Request,
|
||||||
@@ -158,7 +161,10 @@ func registerAllProcessors(combService *comb.CombService) {
|
|||||||
"IVYZ7C9D": ivyz.ProcessIVYZ7C9DRequest,
|
"IVYZ7C9D": ivyz.ProcessIVYZ7C9DRequest,
|
||||||
"IVYZ5E3F": ivyz.ProcessIVYZ5E3FRequest,
|
"IVYZ5E3F": ivyz.ProcessIVYZ5E3FRequest,
|
||||||
"IVYZ7F3A": ivyz.ProcessIVYZ7F3ARequest,
|
"IVYZ7F3A": ivyz.ProcessIVYZ7F3ARequest,
|
||||||
|
"IVYZ3A7F": ivyz.ProcessIVYZ3A7FRequest,
|
||||||
|
"IVYZ9D2E": ivyz.ProcessIVYZ9D2ERequest,
|
||||||
|
"IVYZ81NC": ivyz.ProcessIVYZ81NCRequest,
|
||||||
|
|
||||||
// COMB系列处理器 - 只注册有自定义逻辑的组合包
|
// COMB系列处理器 - 只注册有自定义逻辑的组合包
|
||||||
"COMB86PM": comb.ProcessCOMB86PMRequest, // 有自定义逻辑:重命名ApiCode
|
"COMB86PM": comb.ProcessCOMB86PMRequest, // 有自定义逻辑:重命名ApiCode
|
||||||
|
|
||||||
@@ -168,6 +174,7 @@ func registerAllProcessors(combService *comb.CombService) {
|
|||||||
// DWBG系列处理器 - 多维报告
|
// DWBG系列处理器 - 多维报告
|
||||||
"DWBG6A2C": dwbg.ProcessDWBG6A2CRequest,
|
"DWBG6A2C": dwbg.ProcessDWBG6A2CRequest,
|
||||||
"DWBG8B4D": dwbg.ProcessDWBG8B4DRequest,
|
"DWBG8B4D": dwbg.ProcessDWBG8B4DRequest,
|
||||||
|
"DWBG7F3A": dwbg.ProcessDWBG7F3ARequest,
|
||||||
|
|
||||||
// FLXG系列处理器 - 风险管控 (包含原FXHY功能)
|
// FLXG系列处理器 - 风险管控 (包含原FXHY功能)
|
||||||
"FLXG8B4D": flxg.ProcessFLXG8B4DRequest,
|
"FLXG8B4D": flxg.ProcessFLXG8B4DRequest,
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
"tyapi-server/internal/infrastructure/external/alicloud"
|
"tyapi-server/internal/infrastructure/external/alicloud"
|
||||||
"tyapi-server/internal/infrastructure/external/tianyancha"
|
"tyapi-server/internal/infrastructure/external/tianyancha"
|
||||||
"tyapi-server/internal/infrastructure/external/westdex"
|
"tyapi-server/internal/infrastructure/external/westdex"
|
||||||
|
"tyapi-server/internal/infrastructure/external/xingwei"
|
||||||
"tyapi-server/internal/infrastructure/external/yushan"
|
"tyapi-server/internal/infrastructure/external/yushan"
|
||||||
"tyapi-server/internal/infrastructure/external/zhicha"
|
"tyapi-server/internal/infrastructure/external/zhicha"
|
||||||
"tyapi-server/internal/shared/interfaces"
|
"tyapi-server/internal/shared/interfaces"
|
||||||
@@ -28,6 +29,7 @@ type ProcessorDependencies struct {
|
|||||||
TianYanChaService *tianyancha.TianYanChaService
|
TianYanChaService *tianyancha.TianYanChaService
|
||||||
AlicloudService *alicloud.AlicloudService
|
AlicloudService *alicloud.AlicloudService
|
||||||
ZhichaService *zhicha.ZhichaService
|
ZhichaService *zhicha.ZhichaService
|
||||||
|
XingweiService *xingwei.XingweiService
|
||||||
Validator interfaces.RequestValidator
|
Validator interfaces.RequestValidator
|
||||||
CombService CombServiceInterface // Changed to interface to break import cycle
|
CombService CombServiceInterface // Changed to interface to break import cycle
|
||||||
Options *commands.ApiCallOptions // 添加Options支持
|
Options *commands.ApiCallOptions // 添加Options支持
|
||||||
@@ -41,6 +43,7 @@ func NewProcessorDependencies(
|
|||||||
tianYanChaService *tianyancha.TianYanChaService,
|
tianYanChaService *tianyancha.TianYanChaService,
|
||||||
alicloudService *alicloud.AlicloudService,
|
alicloudService *alicloud.AlicloudService,
|
||||||
zhichaService *zhicha.ZhichaService,
|
zhichaService *zhicha.ZhichaService,
|
||||||
|
xingweiService *xingwei.XingweiService,
|
||||||
validator interfaces.RequestValidator,
|
validator interfaces.RequestValidator,
|
||||||
combService CombServiceInterface, // Changed to interface
|
combService CombServiceInterface, // Changed to interface
|
||||||
) *ProcessorDependencies {
|
) *ProcessorDependencies {
|
||||||
@@ -50,6 +53,7 @@ func NewProcessorDependencies(
|
|||||||
TianYanChaService: tianYanChaService,
|
TianYanChaService: tianYanChaService,
|
||||||
AlicloudService: alicloudService,
|
AlicloudService: alicloudService,
|
||||||
ZhichaService: zhichaService,
|
ZhichaService: zhichaService,
|
||||||
|
XingweiService: xingweiService,
|
||||||
Validator: validator,
|
Validator: validator,
|
||||||
CombService: combService,
|
CombService: combService,
|
||||||
Options: nil, // 初始化为nil,在调用时设置
|
Options: nil, // 初始化为nil,在调用时设置
|
||||||
|
|||||||
@@ -0,0 +1,51 @@
|
|||||||
|
package dwbg
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"tyapi-server/internal/domains/api/dto"
|
||||||
|
"tyapi-server/internal/domains/api/services/processors"
|
||||||
|
"tyapi-server/internal/infrastructure/external/xingwei"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ProcessDWBG7F3ARequest DWBG7F3A API处理方法 - 行为数据查询
|
||||||
|
func ProcessDWBG7F3ARequest(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
|
||||||
|
var paramsDto dto.DWBG7F3AReq
|
||||||
|
if err := json.Unmarshal(params, ¶msDto); err != nil {
|
||||||
|
return nil, errors.Join(processors.ErrSystem, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := deps.Validator.ValidateStruct(paramsDto); err != nil {
|
||||||
|
return nil, errors.Join(processors.ErrInvalidParam, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建请求数据,使用xingwei服务的正确字段名
|
||||||
|
reqData := map[string]interface{}{
|
||||||
|
"name": paramsDto.Name,
|
||||||
|
"idCardNum": paramsDto.IDCard,
|
||||||
|
"phoneNumber": paramsDto.MobileNo,
|
||||||
|
}
|
||||||
|
|
||||||
|
// 调用行为数据API,使用指定的project_id
|
||||||
|
projectID := "CDJ-1101695406546284544"
|
||||||
|
respBytes, err := deps.XingweiService.CallAPI(ctx, projectID, reqData)
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, xingwei.ErrNotFound) {
|
||||||
|
// 查空情况,返回特定的查空错误
|
||||||
|
return nil, errors.Join(processors.ErrNotFound, err)
|
||||||
|
} else if errors.Is(err, xingwei.ErrDatasource) {
|
||||||
|
// 数据源错误
|
||||||
|
return nil, errors.Join(processors.ErrDatasource, err)
|
||||||
|
} else if errors.Is(err, xingwei.ErrSystem) {
|
||||||
|
// 系统错误
|
||||||
|
return nil, errors.Join(processors.ErrSystem, err)
|
||||||
|
} else {
|
||||||
|
// 其他未知错误
|
||||||
|
return nil, errors.Join(processors.ErrSystem, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return respBytes, nil
|
||||||
|
}
|
||||||
@@ -2,14 +2,14 @@ package ivyz
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"errors"
|
||||||
|
|
||||||
"tyapi-server/internal/domains/api/services/processors"
|
"tyapi-server/internal/domains/api/services/processors"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ProcessIVYZ2125Request IVYZ2125 API处理方法
|
// ProcessIVYZ2125Request IVYZ2125 API处理方法
|
||||||
func ProcessIVYZ2125Request(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
|
func ProcessIVYZ2125Request(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
|
||||||
return nil, fmt.Errorf("%s: %w", processors.ErrSystem, "服务已停用")
|
return nil, errors.Join(processors.ErrSystem, errors.New("服务已停用"))
|
||||||
// var paramsDto dto.IVYZ2125Req
|
// var paramsDto dto.IVYZ2125Req
|
||||||
// if err := json.Unmarshal(params, ¶msDto); err != nil {
|
// if err := json.Unmarshal(params, ¶msDto); err != nil {
|
||||||
// return nil, errors.Join(processors.ErrSystem, err)
|
// return nil, errors.Join(processors.ErrSystem, err)
|
||||||
|
|||||||
@@ -0,0 +1,50 @@
|
|||||||
|
package ivyz
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"tyapi-server/internal/domains/api/dto"
|
||||||
|
"tyapi-server/internal/domains/api/services/processors"
|
||||||
|
"tyapi-server/internal/infrastructure/external/xingwei"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ProcessIVYZ3A7FRequest IVYZ3A7F API处理方法 - 行为数据查询
|
||||||
|
func ProcessIVYZ3A7FRequest(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
|
||||||
|
var paramsDto dto.IVYZ3A7FReq
|
||||||
|
if err := json.Unmarshal(params, ¶msDto); err != nil {
|
||||||
|
return nil, errors.Join(processors.ErrSystem, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := deps.Validator.ValidateStruct(paramsDto); err != nil {
|
||||||
|
return nil, errors.Join(processors.ErrInvalidParam, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建请求数据,使用xingwei服务的正确字段名
|
||||||
|
reqData := map[string]interface{}{
|
||||||
|
"name": paramsDto.Name,
|
||||||
|
"idCardNum": paramsDto.IDCard,
|
||||||
|
}
|
||||||
|
|
||||||
|
// 调用行为数据API,使用指定的project_id
|
||||||
|
projectID := "CDJ-1104648854749245440"
|
||||||
|
respBytes, err := deps.XingweiService.CallAPI(ctx, projectID, reqData)
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, xingwei.ErrNotFound) {
|
||||||
|
// 查空情况,返回特定的查空错误
|
||||||
|
return nil, errors.Join(processors.ErrNotFound, err)
|
||||||
|
} else if errors.Is(err, xingwei.ErrDatasource) {
|
||||||
|
// 数据源错误
|
||||||
|
return nil, errors.Join(processors.ErrDatasource, err)
|
||||||
|
} else if errors.Is(err, xingwei.ErrSystem) {
|
||||||
|
// 系统错误
|
||||||
|
return nil, errors.Join(processors.ErrSystem, err)
|
||||||
|
} else {
|
||||||
|
// 其他未知错误
|
||||||
|
return nil, errors.Join(processors.ErrSystem, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return respBytes, nil
|
||||||
|
}
|
||||||
@@ -34,11 +34,11 @@ func ProcessIVYZ5733Request(ctx context.Context, params []byte, deps *processors
|
|||||||
reqData := map[string]interface{}{
|
reqData := map[string]interface{}{
|
||||||
"data": map[string]interface{}{
|
"data": map[string]interface{}{
|
||||||
"name": encryptedName,
|
"name": encryptedName,
|
||||||
"idcard": encryptedIDCard,
|
"idNo": encryptedIDCard,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
respBytes, err := deps.WestDexService.CallAPI(ctx, "G09XM02", reqData)
|
respBytes, err := deps.WestDexService.CallAPI(ctx, "G09GZ02", reqData)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, westdex.ErrDatasource) {
|
if errors.Is(err, westdex.ErrDatasource) {
|
||||||
return nil, errors.Join(processors.ErrDatasource, err)
|
return nil, errors.Join(processors.ErrDatasource, err)
|
||||||
@@ -47,5 +47,37 @@ func ProcessIVYZ5733Request(ctx context.Context, params []byte, deps *processors
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return respBytes, nil
|
// 解析新源响应数据
|
||||||
|
var newResp struct {
|
||||||
|
Status string `json:"status"`
|
||||||
|
}
|
||||||
|
if err := json.Unmarshal(respBytes, &newResp); err != nil {
|
||||||
|
return nil, errors.Join(processors.ErrSystem, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 转换状态码
|
||||||
|
var statusCode string
|
||||||
|
switch newResp.Status {
|
||||||
|
case "结婚":
|
||||||
|
statusCode = "IA"
|
||||||
|
case "离婚":
|
||||||
|
statusCode = "IB"
|
||||||
|
case "未查得":
|
||||||
|
statusCode = "INR"
|
||||||
|
default:
|
||||||
|
statusCode = "INR"
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建旧格式响应
|
||||||
|
oldResp := map[string]interface{}{
|
||||||
|
"code": "0",
|
||||||
|
"data": map[string]interface{}{
|
||||||
|
"data": statusCode + ":匹配不成功",
|
||||||
|
},
|
||||||
|
"seqNo": "",
|
||||||
|
"message": "成功",
|
||||||
|
}
|
||||||
|
|
||||||
|
// 返回旧格式响应
|
||||||
|
return json.Marshal(oldResp)
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
package ivyz
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"tyapi-server/internal/domains/api/dto"
|
||||||
|
"tyapi-server/internal/domains/api/services/processors"
|
||||||
|
"tyapi-server/internal/infrastructure/external/westdex"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ProcessIVYZ81NCRequest IVYZ81NC API处理方法
|
||||||
|
func ProcessIVYZ81NCRequest(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
|
||||||
|
var paramsDto dto.IVYZ81NCReq
|
||||||
|
if err := json.Unmarshal(params, ¶msDto); err != nil {
|
||||||
|
return nil, errors.Join(processors.ErrSystem, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := deps.Validator.ValidateStruct(paramsDto); err != nil {
|
||||||
|
return nil, errors.Join(processors.ErrInvalidParam, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
encryptedName, err := deps.WestDexService.Encrypt(paramsDto.Name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Join(processors.ErrSystem, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
encryptedIDCard, err := deps.WestDexService.Encrypt(paramsDto.IDCard)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Join(processors.ErrSystem, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
reqData := map[string]interface{}{
|
||||||
|
"data": map[string]interface{}{
|
||||||
|
"name": encryptedName,
|
||||||
|
"idcard": encryptedIDCard,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
respBytes, err := deps.WestDexService.CallAPI(ctx, "G09XM02", reqData)
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, westdex.ErrDatasource) {
|
||||||
|
return nil, errors.Join(processors.ErrDatasource, err)
|
||||||
|
} else {
|
||||||
|
return nil, errors.Join(processors.ErrSystem, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return respBytes, nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
package ivyz
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"tyapi-server/internal/domains/api/dto"
|
||||||
|
"tyapi-server/internal/domains/api/services/processors"
|
||||||
|
"tyapi-server/internal/infrastructure/external/xingwei"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ProcessIVYZ9D2ERequest IVYZ9D2E API处理方法 - 行为数据查询
|
||||||
|
func ProcessIVYZ9D2ERequest(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
|
||||||
|
var paramsDto dto.IVYZ9D2EReq
|
||||||
|
if err := json.Unmarshal(params, ¶msDto); err != nil {
|
||||||
|
return nil, errors.Join(processors.ErrSystem, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := deps.Validator.ValidateStruct(paramsDto); err != nil {
|
||||||
|
return nil, errors.Join(processors.ErrInvalidParam, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建请求数据,使用xingwei服务的正确字段名
|
||||||
|
reqData := map[string]interface{}{
|
||||||
|
"name": paramsDto.Name,
|
||||||
|
"idCardNum": paramsDto.IDCard,
|
||||||
|
"scenario": paramsDto.UseScenario,
|
||||||
|
}
|
||||||
|
|
||||||
|
// 调用行为数据API,使用指定的project_id
|
||||||
|
projectID := "CDJ-1104648845446279168"
|
||||||
|
respBytes, err := deps.XingweiService.CallAPI(ctx, projectID, reqData)
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, xingwei.ErrNotFound) {
|
||||||
|
// 查空情况,返回特定的查空错误
|
||||||
|
return nil, errors.Join(processors.ErrNotFound, err)
|
||||||
|
} else if errors.Is(err, xingwei.ErrDatasource) {
|
||||||
|
// 数据源错误
|
||||||
|
return nil, errors.Join(processors.ErrDatasource, err)
|
||||||
|
} else if errors.Is(err, xingwei.ErrSystem) {
|
||||||
|
// 系统错误
|
||||||
|
return nil, errors.Join(processors.ErrSystem, err)
|
||||||
|
} else {
|
||||||
|
// 其他未知错误
|
||||||
|
return nil, errors.Join(processors.ErrSystem, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return respBytes, nil
|
||||||
|
}
|
||||||
@@ -2,14 +2,14 @@ package ivyz
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"errors"
|
||||||
|
|
||||||
"tyapi-server/internal/domains/api/services/processors"
|
"tyapi-server/internal/domains/api/services/processors"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ProcessIVYZADEERequest IVYZADEE API处理方法
|
// ProcessIVYZADEERequest IVYZADEE API处理方法
|
||||||
func ProcessIVYZADEERequest(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
|
func ProcessIVYZADEERequest(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
|
||||||
return nil, fmt.Errorf("%s: %w", processors.ErrSystem, "服务已停用")
|
return nil, errors.Join(processors.ErrSystem, errors.New("服务已停用"))
|
||||||
// var paramsDto dto.IVYZADEEReq
|
// var paramsDto dto.IVYZADEEReq
|
||||||
// if err := json.Unmarshal(params, ¶msDto); err != nil {
|
// if err := json.Unmarshal(params, ¶msDto); err != nil {
|
||||||
// return nil, errors.Join(processors.ErrSystem, err)
|
// return nil, errors.Join(processors.ErrSystem, err)
|
||||||
|
|||||||
@@ -21,26 +21,13 @@ func ProcessJRZQ8A2DRequest(ctx context.Context, params []byte, deps *processors
|
|||||||
return nil, errors.Join(processors.ErrInvalidParam, err)
|
return nil, errors.Join(processors.ErrInvalidParam, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
encryptedName, err := deps.ZhichaService.Encrypt(paramsDto.Name)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Join(processors.ErrSystem, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
encryptedIDCard, err := deps.ZhichaService.Encrypt(paramsDto.IDCard)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Join(processors.ErrSystem, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
encryptedMobileNo, err := deps.ZhichaService.Encrypt(paramsDto.MobileNo)
|
encryptedMobileNo, err := deps.ZhichaService.Encrypt(paramsDto.MobileNo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Join(processors.ErrSystem, err)
|
return nil, errors.Join(processors.ErrSystem, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
reqData := map[string]interface{}{
|
reqData := map[string]interface{}{
|
||||||
"name": encryptedName,
|
"phone": encryptedMobileNo,
|
||||||
"idCard": encryptedIDCard,
|
|
||||||
"phone": encryptedMobileNo,
|
|
||||||
"authorized": paramsDto.Authorized,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
respData, err := deps.ZhichaService.CallAPI(ctx, "ZCI018", reqData)
|
respData, err := deps.ZhichaService.CallAPI(ctx, "ZCI018", reqData)
|
||||||
|
|||||||
@@ -0,0 +1,51 @@
|
|||||||
|
package yysy
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"tyapi-server/internal/domains/api/dto"
|
||||||
|
"tyapi-server/internal/domains/api/services/processors"
|
||||||
|
"tyapi-server/internal/infrastructure/external/xingwei"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ProcessYYSY8F3ARequest YYSY8F3A API处理方法 - 行为数据查询
|
||||||
|
func ProcessYYSY8F3ARequest(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
|
||||||
|
var paramsDto dto.YYSY8F3AReq
|
||||||
|
if err := json.Unmarshal(params, ¶msDto); err != nil {
|
||||||
|
return nil, errors.Join(processors.ErrSystem, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := deps.Validator.ValidateStruct(paramsDto); err != nil {
|
||||||
|
return nil, errors.Join(processors.ErrInvalidParam, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建请求数据,直接传递姓名、身份证、手机号
|
||||||
|
reqData := map[string]interface{}{
|
||||||
|
"name": paramsDto.Name,
|
||||||
|
"idCardNum": paramsDto.IDCard,
|
||||||
|
"phoneNumber": paramsDto.MobileNo,
|
||||||
|
}
|
||||||
|
|
||||||
|
// 调用行为数据API,使用指定的project_id
|
||||||
|
projectID := "CDJ-1100244697766359040"
|
||||||
|
respBytes, err := deps.XingweiService.CallAPI(ctx, projectID, reqData)
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, xingwei.ErrNotFound) {
|
||||||
|
// 查空情况,返回特定的查空错误
|
||||||
|
return nil, errors.Join(processors.ErrNotFound, err)
|
||||||
|
} else if errors.Is(err, xingwei.ErrDatasource) {
|
||||||
|
// 数据源错误
|
||||||
|
return nil, errors.Join(processors.ErrDatasource, err)
|
||||||
|
} else if errors.Is(err, xingwei.ErrSystem) {
|
||||||
|
// 系统错误
|
||||||
|
return nil, errors.Join(processors.ErrSystem, err)
|
||||||
|
} else {
|
||||||
|
// 其他未知错误
|
||||||
|
return nil, errors.Join(processors.ErrSystem, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return respBytes, nil
|
||||||
|
}
|
||||||
62
internal/infrastructure/external/xingwei/xingwei_factory.go
vendored
Normal file
62
internal/infrastructure/external/xingwei/xingwei_factory.go
vendored
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
package xingwei
|
||||||
|
|
||||||
|
import (
|
||||||
|
"tyapi-server/internal/config"
|
||||||
|
"tyapi-server/internal/shared/external_logger"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewXingweiServiceWithConfig 使用配置创建行为数据服务
|
||||||
|
func NewXingweiServiceWithConfig(cfg *config.Config) (*XingweiService, error) {
|
||||||
|
// 将配置类型转换为通用外部服务日志配置
|
||||||
|
loggingConfig := external_logger.ExternalServiceLoggingConfig{
|
||||||
|
Enabled: cfg.Xingwei.Logging.Enabled,
|
||||||
|
LogDir: cfg.Xingwei.Logging.LogDir,
|
||||||
|
ServiceName: "xingwei",
|
||||||
|
UseDaily: cfg.Xingwei.Logging.UseDaily,
|
||||||
|
EnableLevelSeparation: cfg.Xingwei.Logging.EnableLevelSeparation,
|
||||||
|
LevelConfigs: make(map[string]external_logger.ExternalServiceLevelFileConfig),
|
||||||
|
}
|
||||||
|
|
||||||
|
// 转换级别配置
|
||||||
|
for key, value := range cfg.Xingwei.Logging.LevelConfigs {
|
||||||
|
loggingConfig.LevelConfigs[key] = external_logger.ExternalServiceLevelFileConfig{
|
||||||
|
MaxSize: value.MaxSize,
|
||||||
|
MaxBackups: value.MaxBackups,
|
||||||
|
MaxAge: value.MaxAge,
|
||||||
|
Compress: value.Compress,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建通用外部服务日志器
|
||||||
|
logger, err := external_logger.NewExternalServiceLogger(loggingConfig)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建行为数据服务
|
||||||
|
service := NewXingweiService(
|
||||||
|
cfg.Xingwei.URL,
|
||||||
|
cfg.Xingwei.ApiID,
|
||||||
|
cfg.Xingwei.ApiKey,
|
||||||
|
logger,
|
||||||
|
)
|
||||||
|
|
||||||
|
return service, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewXingweiServiceWithLogging 使用自定义日志配置创建行为数据服务
|
||||||
|
func NewXingweiServiceWithLogging(url, apiID, apiKey string, loggingConfig external_logger.ExternalServiceLoggingConfig) (*XingweiService, error) {
|
||||||
|
// 设置服务名称
|
||||||
|
loggingConfig.ServiceName = "xingwei"
|
||||||
|
|
||||||
|
// 创建通用外部服务日志器
|
||||||
|
logger, err := external_logger.NewExternalServiceLogger(loggingConfig)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建行为数据服务
|
||||||
|
service := NewXingweiService(url, apiID, apiKey, logger)
|
||||||
|
|
||||||
|
return service, nil
|
||||||
|
}
|
||||||
279
internal/infrastructure/external/xingwei/xingwei_service.go
vendored
Normal file
279
internal/infrastructure/external/xingwei/xingwei_service.go
vendored
Normal file
@@ -0,0 +1,279 @@
|
|||||||
|
package xingwei
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"crypto/md5"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
"sync/atomic"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"tyapi-server/internal/shared/external_logger"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 行为数据API状态码常量
|
||||||
|
const (
|
||||||
|
CodeSuccess = 200 // 操作成功
|
||||||
|
CodeSystemError = 500 // 系统内部错误
|
||||||
|
CodeMerchantError = 3001 // 商家相关报错(商家不存在、商家被禁用、商家余额不足)
|
||||||
|
CodeAccountExpired = 3002 // 账户已过期
|
||||||
|
CodeIPWhitelistMissing = 3003 // 未添加ip白名单
|
||||||
|
CodeUnauthorized = 3004 // 未授权调用该接口
|
||||||
|
CodeProductIDError = 4001 // 产品id错误
|
||||||
|
CodeInterfaceDisabled = 4002 // 接口被停用
|
||||||
|
CodeQueryException = 5001 // 接口查询异常,请联系技术人员
|
||||||
|
CodeNotFound = 6000 // 未查询到结果
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrDatasource = errors.New("数据源异常")
|
||||||
|
ErrSystem = errors.New("系统异常")
|
||||||
|
ErrNotFound = errors.New("未查询到结果")
|
||||||
|
|
||||||
|
// 请求ID计数器,确保唯一性
|
||||||
|
requestIDCounter int64
|
||||||
|
)
|
||||||
|
|
||||||
|
// XingweiResponse 行为数据API响应结构
|
||||||
|
type XingweiResponse struct {
|
||||||
|
Msg string `json:"msg"`
|
||||||
|
Code int `json:"code"`
|
||||||
|
Data interface{} `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// XingweiErrorCode 行为数据错误码定义
|
||||||
|
type XingweiErrorCode struct {
|
||||||
|
Code int
|
||||||
|
Message string
|
||||||
|
}
|
||||||
|
|
||||||
|
// 行为数据错误码映射
|
||||||
|
var XingweiErrorCodes = map[int]XingweiErrorCode{
|
||||||
|
CodeSuccess: {Code: CodeSuccess, Message: "操作成功"},
|
||||||
|
CodeSystemError: {Code: CodeSystemError, Message: "系统内部错误"},
|
||||||
|
CodeMerchantError: {Code: CodeMerchantError, Message: "商家相关报错(商家不存在、商家被禁用、商家余额不足)"},
|
||||||
|
CodeAccountExpired: {Code: CodeAccountExpired, Message: "账户已过期"},
|
||||||
|
CodeIPWhitelistMissing: {Code: CodeIPWhitelistMissing, Message: "未添加ip白名单"},
|
||||||
|
CodeUnauthorized: {Code: CodeUnauthorized, Message: "未授权调用该接口"},
|
||||||
|
CodeProductIDError: {Code: CodeProductIDError, Message: "产品id错误"},
|
||||||
|
CodeInterfaceDisabled: {Code: CodeInterfaceDisabled, Message: "接口被停用"},
|
||||||
|
CodeQueryException: {Code: CodeQueryException, Message: "接口查询异常,请联系技术人员"},
|
||||||
|
CodeNotFound: {Code: CodeNotFound, Message: "未查询到结果"},
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetXingweiErrorMessage 根据错误码获取错误消息
|
||||||
|
func GetXingweiErrorMessage(code int) string {
|
||||||
|
if errorCode, exists := XingweiErrorCodes[code]; exists {
|
||||||
|
return errorCode.Message
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("未知错误码: %d", code)
|
||||||
|
}
|
||||||
|
|
||||||
|
type XingweiConfig struct {
|
||||||
|
URL string
|
||||||
|
ApiID string
|
||||||
|
ApiKey string
|
||||||
|
}
|
||||||
|
|
||||||
|
type XingweiService struct {
|
||||||
|
config XingweiConfig
|
||||||
|
logger *external_logger.ExternalServiceLogger
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewXingweiService 是一个构造函数,用于初始化 XingweiService
|
||||||
|
func NewXingweiService(url, apiID, apiKey string, logger *external_logger.ExternalServiceLogger) *XingweiService {
|
||||||
|
return &XingweiService{
|
||||||
|
config: XingweiConfig{
|
||||||
|
URL: url,
|
||||||
|
ApiID: apiID,
|
||||||
|
ApiKey: apiKey,
|
||||||
|
},
|
||||||
|
logger: logger,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// generateRequestID 生成请求ID
|
||||||
|
func (x *XingweiService) generateRequestID() string {
|
||||||
|
timestamp := time.Now().UnixNano()
|
||||||
|
// 使用原子计数器确保唯一性
|
||||||
|
counter := atomic.AddInt64(&requestIDCounter, 1)
|
||||||
|
hash := md5.Sum([]byte(fmt.Sprintf("%d_%d_%s", timestamp, counter, x.config.ApiID)))
|
||||||
|
return fmt.Sprintf("xingwei_%x", hash[:8])
|
||||||
|
}
|
||||||
|
|
||||||
|
// createSign 创建签名:使用MD5算法将apiId、timestamp、apiKey字符串拼接生成sign
|
||||||
|
// 参考Java示例:DigestUtils.md5Hex(apiId + timestamp + apiKey)
|
||||||
|
func (x *XingweiService) createSign(timestamp int64) string {
|
||||||
|
signStr := x.config.ApiID + strconv.FormatInt(timestamp, 10) + x.config.ApiKey
|
||||||
|
hash := md5.Sum([]byte(signStr))
|
||||||
|
return fmt.Sprintf("%x", hash)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CallAPI 调用行为数据的 API
|
||||||
|
func (x *XingweiService) CallAPI(ctx context.Context, projectID string, params map[string]interface{}) (resp []byte, err error) {
|
||||||
|
startTime := time.Now()
|
||||||
|
requestID := x.generateRequestID()
|
||||||
|
timestamp := time.Now().UnixMilli()
|
||||||
|
|
||||||
|
// 从ctx中获取transactionId
|
||||||
|
var transactionID string
|
||||||
|
if ctxTransactionID, ok := ctx.Value("transaction_id").(string); ok {
|
||||||
|
transactionID = ctxTransactionID
|
||||||
|
}
|
||||||
|
|
||||||
|
// 记录请求日志
|
||||||
|
if x.logger != nil {
|
||||||
|
x.logger.LogRequest(requestID, transactionID, "xingwei_api", x.config.URL, params)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将请求参数转换为JSON
|
||||||
|
jsonData, marshalErr := json.Marshal(params)
|
||||||
|
if marshalErr != nil {
|
||||||
|
err = errors.Join(ErrSystem, marshalErr)
|
||||||
|
if x.logger != nil {
|
||||||
|
x.logger.LogError(requestID, transactionID, "xingwei_api", err, params)
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建HTTP POST请求
|
||||||
|
req, newRequestErr := http.NewRequestWithContext(ctx, "POST", x.config.URL, bytes.NewBuffer(jsonData))
|
||||||
|
if newRequestErr != nil {
|
||||||
|
err = errors.Join(ErrSystem, newRequestErr)
|
||||||
|
if x.logger != nil {
|
||||||
|
x.logger.LogError(requestID, transactionID, "xingwei_api", err, params)
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置请求头
|
||||||
|
req.Header.Set("Content-Type", "application/json")
|
||||||
|
req.Header.Set("timestamp", strconv.FormatInt(timestamp, 10))
|
||||||
|
req.Header.Set("sign", x.createSign(timestamp))
|
||||||
|
req.Header.Set("API-ID", x.config.ApiID)
|
||||||
|
req.Header.Set("project_id", projectID)
|
||||||
|
|
||||||
|
// 创建HTTP客户端
|
||||||
|
client := &http.Client{
|
||||||
|
Timeout: 20 * time.Second,
|
||||||
|
}
|
||||||
|
|
||||||
|
// 发送请求
|
||||||
|
httpResp, clientDoErr := client.Do(req)
|
||||||
|
if clientDoErr != nil {
|
||||||
|
err = errors.Join(ErrSystem, clientDoErr)
|
||||||
|
if x.logger != nil {
|
||||||
|
x.logger.LogError(requestID, transactionID, "xingwei_api", err, params)
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer func(Body io.ReadCloser) {
|
||||||
|
closeErr := Body.Close()
|
||||||
|
if closeErr != nil {
|
||||||
|
// 记录关闭错误
|
||||||
|
if x.logger != nil {
|
||||||
|
x.logger.LogError(requestID, transactionID, "xingwei_api", errors.Join(ErrSystem, fmt.Errorf("关闭响应体失败: %w", closeErr)), params)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}(httpResp.Body)
|
||||||
|
|
||||||
|
// 计算请求耗时
|
||||||
|
duration := time.Since(startTime)
|
||||||
|
|
||||||
|
// 读取响应体
|
||||||
|
bodyBytes, ReadErr := io.ReadAll(httpResp.Body)
|
||||||
|
if ReadErr != nil {
|
||||||
|
err = errors.Join(ErrSystem, ReadErr)
|
||||||
|
if x.logger != nil {
|
||||||
|
x.logger.LogError(requestID, transactionID, "xingwei_api", err, params)
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 记录响应日志
|
||||||
|
if x.logger != nil {
|
||||||
|
x.logger.LogResponse(requestID, transactionID, "xingwei_api", httpResp.StatusCode, bodyBytes, duration)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查HTTP状态码
|
||||||
|
if httpResp.StatusCode != http.StatusOK {
|
||||||
|
err = errors.Join(ErrSystem, fmt.Errorf("行为数据请求失败,状态码: %d", httpResp.StatusCode))
|
||||||
|
if x.logger != nil {
|
||||||
|
x.logger.LogError(requestID, transactionID, "xingwei_api", err, params)
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解析响应结构
|
||||||
|
var xingweiResp XingweiResponse
|
||||||
|
if err := json.Unmarshal(bodyBytes, &xingweiResp); err != nil {
|
||||||
|
err = errors.Join(ErrSystem, fmt.Errorf("响应解析失败: %w", err))
|
||||||
|
if x.logger != nil {
|
||||||
|
x.logger.LogError(requestID, transactionID, "xingwei_api", err, params)
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查业务状态码
|
||||||
|
switch xingweiResp.Code {
|
||||||
|
case CodeSuccess:
|
||||||
|
// 成功响应,返回data字段
|
||||||
|
if xingweiResp.Data == nil {
|
||||||
|
return []byte("{}"), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将data转换为JSON字节
|
||||||
|
dataBytes, err := json.Marshal(xingweiResp.Data)
|
||||||
|
if err != nil {
|
||||||
|
err = errors.Join(ErrSystem, fmt.Errorf("data字段序列化失败: %w", err))
|
||||||
|
if x.logger != nil {
|
||||||
|
x.logger.LogError(requestID, transactionID, "xingwei_api", err, params)
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return dataBytes, nil
|
||||||
|
|
||||||
|
case CodeNotFound:
|
||||||
|
// 未查询到结果,返回查空错误
|
||||||
|
if x.logger != nil {
|
||||||
|
x.logger.LogError(requestID, transactionID, "xingwei_api",
|
||||||
|
errors.Join(ErrNotFound, fmt.Errorf("未查询到结果")), params)
|
||||||
|
}
|
||||||
|
return nil, errors.Join(ErrNotFound, fmt.Errorf("未查询到结果"))
|
||||||
|
|
||||||
|
case CodeSystemError:
|
||||||
|
// 系统内部错误
|
||||||
|
errorMsg := GetXingweiErrorMessage(xingweiResp.Code)
|
||||||
|
systemErr := fmt.Errorf("行为数据系统错误[%d]: %s", xingweiResp.Code, errorMsg)
|
||||||
|
|
||||||
|
if x.logger != nil {
|
||||||
|
x.logger.LogError(requestID, transactionID, "xingwei_api",
|
||||||
|
errors.Join(ErrSystem, systemErr), params)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, errors.Join(ErrSystem, systemErr)
|
||||||
|
|
||||||
|
default:
|
||||||
|
// 其他业务错误
|
||||||
|
errorMsg := GetXingweiErrorMessage(xingweiResp.Code)
|
||||||
|
businessErr := fmt.Errorf("行为数据业务错误[%d]: %s", xingweiResp.Code, errorMsg)
|
||||||
|
|
||||||
|
if x.logger != nil {
|
||||||
|
x.logger.LogError(requestID, transactionID, "xingwei_api",
|
||||||
|
errors.Join(ErrDatasource, businessErr), params)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, errors.Join(ErrDatasource, businessErr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetConfig 获取配置信息
|
||||||
|
func (x *XingweiService) GetConfig() XingweiConfig {
|
||||||
|
return x.config
|
||||||
|
}
|
||||||
241
internal/infrastructure/external/xingwei/xingwei_test.go
vendored
Normal file
241
internal/infrastructure/external/xingwei/xingwei_test.go
vendored
Normal file
@@ -0,0 +1,241 @@
|
|||||||
|
package xingwei
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestXingweiService_CreateSign(t *testing.T) {
|
||||||
|
// 创建测试配置 - 使用nil logger来避免日志问题
|
||||||
|
service := NewXingweiService(
|
||||||
|
"https://sjztyh.chengdaoji.cn/dataCenterManageApi/manage/interface/doc/api/handle",
|
||||||
|
"test_api_id",
|
||||||
|
"test_api_key",
|
||||||
|
nil, // 使用nil logger
|
||||||
|
)
|
||||||
|
|
||||||
|
// 测试签名生成
|
||||||
|
timestamp := int64(1743474772049)
|
||||||
|
sign := service.createSign(timestamp)
|
||||||
|
|
||||||
|
// 验证签名不为空
|
||||||
|
if sign == "" {
|
||||||
|
t.Error("签名不能为空")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 验证签名长度(MD5应该是32位十六进制字符串)
|
||||||
|
if len(sign) != 32 {
|
||||||
|
t.Errorf("签名长度应该是32位,实际是%d位", len(sign))
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Logf("生成的签名: %s", sign)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestXingweiService_CallAPI(t *testing.T) {
|
||||||
|
// 创建测试配置 - 使用nil logger来避免日志问题
|
||||||
|
service := NewXingweiService(
|
||||||
|
"https://sjztyh.chengdaoji.cn/dataCenterManageApi/manage/interface/doc/api/handle",
|
||||||
|
"test_api_id",
|
||||||
|
"test_api_key",
|
||||||
|
nil, // 使用nil logger
|
||||||
|
)
|
||||||
|
|
||||||
|
// 创建测试上下文
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
// 测试参数
|
||||||
|
projectID := "test_project_id"
|
||||||
|
params := map[string]interface{}{
|
||||||
|
"test_param": "test_value",
|
||||||
|
}
|
||||||
|
|
||||||
|
// 注意:这个测试会实际发送HTTP请求,所以可能会失败
|
||||||
|
// 在实际使用中,应该使用mock或者测试服务器
|
||||||
|
resp, err := service.CallAPI(ctx, projectID, params)
|
||||||
|
|
||||||
|
// 由于这是真实的外部API调用,我们主要测试错误处理
|
||||||
|
if err != nil {
|
||||||
|
t.Logf("预期的错误(真实API调用): %v", err)
|
||||||
|
} else {
|
||||||
|
t.Logf("API调用成功,响应长度: %d", len(resp))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestXingweiService_GenerateRequestID(t *testing.T) {
|
||||||
|
// 创建测试配置 - 使用nil logger来避免日志问题
|
||||||
|
service := NewXingweiService(
|
||||||
|
"https://sjztyh.chengdaoji.cn/dataCenterManageApi/manage/interface/doc/api/handle",
|
||||||
|
"test_api_id",
|
||||||
|
"test_api_key",
|
||||||
|
nil, // 使用nil logger
|
||||||
|
)
|
||||||
|
|
||||||
|
// 测试请求ID生成
|
||||||
|
requestID1 := service.generateRequestID()
|
||||||
|
requestID2 := service.generateRequestID()
|
||||||
|
|
||||||
|
// 验证请求ID不为空
|
||||||
|
if requestID1 == "" || requestID2 == "" {
|
||||||
|
t.Error("请求ID不能为空")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 验证请求ID应该以xingwei_开头
|
||||||
|
if len(requestID1) < 8 || requestID1[:8] != "xingwei_" {
|
||||||
|
t.Error("请求ID应该以xingwei_开头")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 验证两次生成的请求ID应该不同
|
||||||
|
if requestID1 == requestID2 {
|
||||||
|
t.Error("两次生成的请求ID应该不同")
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Logf("请求ID1: %s", requestID1)
|
||||||
|
t.Logf("请求ID2: %s", requestID2)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetXingweiErrorMessage(t *testing.T) {
|
||||||
|
// 测试已知错误码(使用常量)
|
||||||
|
testCases := []struct {
|
||||||
|
code int
|
||||||
|
expected string
|
||||||
|
}{
|
||||||
|
{CodeSuccess, "操作成功"},
|
||||||
|
{CodeSystemError, "系统内部错误"},
|
||||||
|
{CodeMerchantError, "商家相关报错(商家不存在、商家被禁用、商家余额不足)"},
|
||||||
|
{CodeAccountExpired, "账户已过期"},
|
||||||
|
{CodeIPWhitelistMissing, "未添加ip白名单"},
|
||||||
|
{CodeUnauthorized, "未授权调用该接口"},
|
||||||
|
{CodeProductIDError, "产品id错误"},
|
||||||
|
{CodeInterfaceDisabled, "接口被停用"},
|
||||||
|
{CodeQueryException, "接口查询异常,请联系技术人员"},
|
||||||
|
{CodeNotFound, "未查询到结果"},
|
||||||
|
{9999, "未知错误码: 9999"}, // 测试未知错误码
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
result := GetXingweiErrorMessage(tc.code)
|
||||||
|
if result != tc.expected {
|
||||||
|
t.Errorf("错误码 %d 的消息不正确,期望: %s, 实际: %s", tc.code, tc.expected, result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestXingweiResponseParsing(t *testing.T) {
|
||||||
|
// 测试响应结构解析
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
response string
|
||||||
|
expectedCode int
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "成功响应",
|
||||||
|
response: `{"msg": "操作成功", "code": 200, "data": {"result": "test"}}`,
|
||||||
|
expectedCode: CodeSuccess,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "商家错误",
|
||||||
|
response: `{"msg": "商家相关报错", "code": 3001, "data": null}`,
|
||||||
|
expectedCode: CodeMerchantError,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "未查询到结果",
|
||||||
|
response: `{"msg": "未查询到结果", "code": 6000, "data": null}`,
|
||||||
|
expectedCode: CodeNotFound,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
var resp XingweiResponse
|
||||||
|
err := json.Unmarshal([]byte(tc.response), &resp)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("解析响应失败: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.Code != tc.expectedCode {
|
||||||
|
t.Errorf("错误码不匹配,期望: %d, 实际: %d", tc.expectedCode, resp.Code)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 测试错误消息获取
|
||||||
|
errorMsg := GetXingweiErrorMessage(resp.Code)
|
||||||
|
if errorMsg == "" {
|
||||||
|
t.Errorf("无法获取错误码 %d 的消息", resp.Code)
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Logf("响应: %+v, 错误消息: %s", resp, errorMsg)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestXingweiErrorHandling 测试错误处理逻辑
|
||||||
|
func TestXingweiErrorHandling(t *testing.T) {
|
||||||
|
// 注意:这个测试主要验证常量定义和错误消息,不需要实际的服务实例
|
||||||
|
|
||||||
|
// 测试查空错误
|
||||||
|
t.Run("NotFound错误", func(t *testing.T) {
|
||||||
|
// 模拟返回查空响应
|
||||||
|
response := `{"msg": "未查询到结果", "code": 6000, "data": null}`
|
||||||
|
var xingweiResp XingweiResponse
|
||||||
|
err := json.Unmarshal([]byte(response), &xingweiResp)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("解析响应失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 验证状态码
|
||||||
|
if xingweiResp.Code != CodeNotFound {
|
||||||
|
t.Errorf("期望状态码 %d, 实际 %d", CodeNotFound, xingweiResp.Code)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 验证错误消息
|
||||||
|
errorMsg := GetXingweiErrorMessage(xingweiResp.Code)
|
||||||
|
if errorMsg != "未查询到结果" {
|
||||||
|
t.Errorf("期望错误消息 '未查询到结果', 实际 '%s'", errorMsg)
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Logf("查空错误测试通过: 状态码=%d, 消息=%s", xingweiResp.Code, errorMsg)
|
||||||
|
})
|
||||||
|
|
||||||
|
// 测试系统错误
|
||||||
|
t.Run("SystemError错误", func(t *testing.T) {
|
||||||
|
response := `{"msg": "系统内部错误", "code": 500, "data": null}`
|
||||||
|
var xingweiResp XingweiResponse
|
||||||
|
err := json.Unmarshal([]byte(response), &xingweiResp)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("解析响应失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if xingweiResp.Code != CodeSystemError {
|
||||||
|
t.Errorf("期望状态码 %d, 实际 %d", CodeSystemError, xingweiResp.Code)
|
||||||
|
}
|
||||||
|
|
||||||
|
errorMsg := GetXingweiErrorMessage(xingweiResp.Code)
|
||||||
|
if errorMsg != "系统内部错误" {
|
||||||
|
t.Errorf("期望错误消息 '系统内部错误', 实际 '%s'", errorMsg)
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Logf("系统错误测试通过: 状态码=%d, 消息=%s", xingweiResp.Code, errorMsg)
|
||||||
|
})
|
||||||
|
|
||||||
|
// 测试成功响应
|
||||||
|
t.Run("Success响应", func(t *testing.T) {
|
||||||
|
response := `{"msg": "操作成功", "code": 200, "data": {"result": "test"}}`
|
||||||
|
var xingweiResp XingweiResponse
|
||||||
|
err := json.Unmarshal([]byte(response), &xingweiResp)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("解析响应失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if xingweiResp.Code != CodeSuccess {
|
||||||
|
t.Errorf("期望状态码 %d, 实际 %d", CodeSuccess, xingweiResp.Code)
|
||||||
|
}
|
||||||
|
|
||||||
|
errorMsg := GetXingweiErrorMessage(xingweiResp.Code)
|
||||||
|
if errorMsg != "操作成功" {
|
||||||
|
t.Errorf("期望错误消息 '操作成功', 实际 '%s'", errorMsg)
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Logf("成功响应测试通过: 状态码=%d, 消息=%s", xingweiResp.Code, errorMsg)
|
||||||
|
})
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user