feat: 添加 muzi 服务并接入 ivyz3p9m
This commit is contained in:
28
config.yaml
28
config.yaml
@@ -411,6 +411,34 @@ zhicha:
|
|||||||
max_age: 30
|
max_age: 30
|
||||||
compress: true
|
compress: true
|
||||||
|
|
||||||
|
# ===========================================
|
||||||
|
# 🌐 木子数据配置
|
||||||
|
# ===========================================
|
||||||
|
muzi:
|
||||||
|
url: "https://carv.m0101.com/magic/carv/pubin/service/academic"
|
||||||
|
app_id: "713014138179585"
|
||||||
|
app_secret: "bd4090ac652c404c80e90ebbdcd6ba1d"
|
||||||
|
timeout: 60s
|
||||||
|
|
||||||
|
logging:
|
||||||
|
enabled: true
|
||||||
|
log_dir: "logs/external_services"
|
||||||
|
service_name: "muzi"
|
||||||
|
use_daily: true
|
||||||
|
enable_level_separation: true
|
||||||
|
|
||||||
|
level_configs:
|
||||||
|
info:
|
||||||
|
max_size: 50
|
||||||
|
max_backups: 3
|
||||||
|
max_age: 7
|
||||||
|
compress: true
|
||||||
|
error:
|
||||||
|
max_size: 100
|
||||||
|
max_backups: 5
|
||||||
|
max_age: 30
|
||||||
|
compress: true
|
||||||
|
|
||||||
# ===========================================
|
# ===========================================
|
||||||
# 🎯 行为数据配置
|
# 🎯 行为数据配置
|
||||||
# ===========================================
|
# ===========================================
|
||||||
|
|||||||
@@ -622,7 +622,7 @@ func (s *ProductApplicationServiceImpl) mergePackageItemsDocumentation(ctx conte
|
|||||||
// 合并文档内容
|
// 合并文档内容
|
||||||
mergedDoc := &responses.DocumentationResponse{
|
mergedDoc := &responses.DocumentationResponse{
|
||||||
ProductID: packageItems[0].ProductID, // 使用第一个子产品的ID作为标识
|
ProductID: packageItems[0].ProductID, // 使用第一个子产品的ID作为标识
|
||||||
RequestMethod: "POST", // 默认方法
|
RequestMethod: "POST", // 默认方法
|
||||||
Version: "1.0",
|
Version: "1.0",
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -755,7 +755,7 @@ func (s *ProductApplicationServiceImpl) buildCombPackageResponseExample(subProdu
|
|||||||
}
|
}
|
||||||
builder.WriteString(" {\n")
|
builder.WriteString(" {\n")
|
||||||
builder.WriteString(fmt.Sprintf(" \"api_code\": \"%s\",\n", spDoc.item.ProductCode))
|
builder.WriteString(fmt.Sprintf(" \"api_code\": \"%s\",\n", spDoc.item.ProductCode))
|
||||||
|
|
||||||
// 第一个示例显示成功,其他可能显示部分失败
|
// 第一个示例显示成功,其他可能显示部分失败
|
||||||
if i == 0 {
|
if i == 0 {
|
||||||
builder.WriteString(" \"success\": true,\n")
|
builder.WriteString(" \"success\": true,\n")
|
||||||
@@ -804,7 +804,7 @@ func (s *ProductApplicationServiceImpl) buildCombPackageResponseExample(subProdu
|
|||||||
if len(subProductDocs) > 0 {
|
if len(subProductDocs) > 0 {
|
||||||
builder.WriteString("## 各子产品详细响应示例\n\n")
|
builder.WriteString("## 各子产品详细响应示例\n\n")
|
||||||
builder.WriteString("以下为各个子产品的详细响应示例,组合包响应中的 `data` 字段即为对应子产品的完整响应数据。\n\n")
|
builder.WriteString("以下为各个子产品的详细响应示例,组合包响应中的 `data` 字段即为对应子产品的完整响应数据。\n\n")
|
||||||
|
|
||||||
for i, spDoc := range subProductDocs {
|
for i, spDoc := range subProductDocs {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
builder.WriteString("\n---\n\n")
|
builder.WriteString("\n---\n\n")
|
||||||
@@ -823,10 +823,6 @@ func (s *ProductApplicationServiceImpl) buildCombPackageResponseExample(subProdu
|
|||||||
return builder.String()
|
return builder.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// paramField 参数字段信息
|
// paramField 参数字段信息
|
||||||
type paramField struct {
|
type paramField struct {
|
||||||
Name string
|
Name string
|
||||||
@@ -1017,6 +1013,7 @@ func (s *ProductApplicationServiceImpl) getDTOMap() map[string]interface{} {
|
|||||||
"FLXG8B4D": &dto.FLXG8B4DReq{},
|
"FLXG8B4D": &dto.FLXG8B4DReq{},
|
||||||
"IVYZ81NC": &dto.IVYZ81NCReq{},
|
"IVYZ81NC": &dto.IVYZ81NCReq{},
|
||||||
"IVYZ7F3A": &dto.IVYZ7F3AReq{},
|
"IVYZ7F3A": &dto.IVYZ7F3AReq{},
|
||||||
|
"IVYZ3P9M": &dto.IVYZ3P9MReq{},
|
||||||
"IVYZ3A7F": &dto.IVYZ3A7FReq{},
|
"IVYZ3A7F": &dto.IVYZ3A7FReq{},
|
||||||
"IVYZ9D2E": &dto.IVYZ9D2EReq{},
|
"IVYZ9D2E": &dto.IVYZ9D2EReq{},
|
||||||
"DWBG7F3A": &dto.DWBG7F3AReq{},
|
"DWBG7F3A": &dto.DWBG7F3AReq{},
|
||||||
@@ -1127,7 +1124,7 @@ func (s *ProductApplicationServiceImpl) generateFieldDescription(jsonTag string,
|
|||||||
descMap := map[string]string{
|
descMap := map[string]string{
|
||||||
"mobile_no": "手机号码(11位)",
|
"mobile_no": "手机号码(11位)",
|
||||||
"id_card": "身份证号码(18位)",
|
"id_card": "身份证号码(18位)",
|
||||||
"name": "姓名",
|
"name": "姓名",
|
||||||
"man_name": "男方姓名",
|
"man_name": "男方姓名",
|
||||||
"woman_name": "女方姓名",
|
"woman_name": "女方姓名",
|
||||||
"man_id_card": "男方身份证号码",
|
"man_id_card": "男方身份证号码",
|
||||||
@@ -1183,4 +1180,4 @@ func (s *ProductApplicationServiceImpl) mapFieldTypeToDocType(frontendType strin
|
|||||||
default:
|
default:
|
||||||
return "string"
|
return "string"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ type Config struct {
|
|||||||
Wallet WalletConfig `mapstructure:"wallet"`
|
Wallet WalletConfig `mapstructure:"wallet"`
|
||||||
WestDex WestDexConfig `mapstructure:"westdex"`
|
WestDex WestDexConfig `mapstructure:"westdex"`
|
||||||
Zhicha ZhichaConfig `mapstructure:"zhicha"`
|
Zhicha ZhichaConfig `mapstructure:"zhicha"`
|
||||||
|
Muzi MuziConfig `mapstructure:"muzi"`
|
||||||
AliPay AliPayConfig `mapstructure:"alipay"`
|
AliPay AliPayConfig `mapstructure:"alipay"`
|
||||||
Yushan YushanConfig `mapstructure:"yushan"`
|
Yushan YushanConfig `mapstructure:"yushan"`
|
||||||
TianYanCha TianYanChaConfig `mapstructure:"tianyancha"`
|
TianYanCha TianYanChaConfig `mapstructure:"tianyancha"`
|
||||||
@@ -141,9 +142,9 @@ type DailyRateLimitConfig struct {
|
|||||||
EnableProxyCheck bool `mapstructure:"enable_proxy_check"` // 是否检查代理
|
EnableProxyCheck bool `mapstructure:"enable_proxy_check"` // 是否检查代理
|
||||||
MaxConcurrent int `mapstructure:"max_concurrent"` // 最大并发请求数
|
MaxConcurrent int `mapstructure:"max_concurrent"` // 最大并发请求数
|
||||||
// 路径排除配置
|
// 路径排除配置
|
||||||
ExcludePaths []string `mapstructure:"exclude_paths"` // 排除频率限制的路径
|
ExcludePaths []string `mapstructure:"exclude_paths"` // 排除频率限制的路径
|
||||||
// 域名排除配置
|
// 域名排除配置
|
||||||
ExcludeDomains []string `mapstructure:"exclude_domains"` // 排除频率限制的域名
|
ExcludeDomains []string `mapstructure:"exclude_domains"` // 排除频率限制的域名
|
||||||
}
|
}
|
||||||
|
|
||||||
// MonitoringConfig 监控配置
|
// MonitoringConfig 监控配置
|
||||||
@@ -324,9 +325,9 @@ type WalletConfig struct {
|
|||||||
|
|
||||||
// BalanceAlertConfig 余额预警配置
|
// BalanceAlertConfig 余额预警配置
|
||||||
type BalanceAlertConfig struct {
|
type BalanceAlertConfig struct {
|
||||||
DefaultEnabled bool `mapstructure:"default_enabled"` // 默认启用余额预警
|
DefaultEnabled bool `mapstructure:"default_enabled"` // 默认启用余额预警
|
||||||
DefaultThreshold float64 `mapstructure:"default_threshold"` // 默认预警阈值
|
DefaultThreshold float64 `mapstructure:"default_threshold"` // 默认预警阈值
|
||||||
AlertCooldownHours int `mapstructure:"alert_cooldown_hours"` // 预警冷却时间(小时)
|
AlertCooldownHours int `mapstructure:"alert_cooldown_hours"` // 预警冷却时间(小时)
|
||||||
}
|
}
|
||||||
|
|
||||||
// AliPayRechargeBonusRule 支付宝充值赠送规则
|
// AliPayRechargeBonusRule 支付宝充值赠送规则
|
||||||
@@ -391,6 +392,33 @@ type ZhichaLevelFileConfig struct {
|
|||||||
Compress bool `mapstructure:"compress"`
|
Compress bool `mapstructure:"compress"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MuziConfig 木子数据配置
|
||||||
|
type MuziConfig struct {
|
||||||
|
URL string `mapstructure:"url"`
|
||||||
|
AppID string `mapstructure:"app_id"`
|
||||||
|
AppSecret string `mapstructure:"app_secret"`
|
||||||
|
Timeout time.Duration `mapstructure:"timeout"`
|
||||||
|
|
||||||
|
Logging MuziLoggingConfig `mapstructure:"logging"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// MuziLoggingConfig 木子数据日志配置
|
||||||
|
type MuziLoggingConfig struct {
|
||||||
|
Enabled bool `mapstructure:"enabled"`
|
||||||
|
LogDir string `mapstructure:"log_dir"`
|
||||||
|
UseDaily bool `mapstructure:"use_daily"`
|
||||||
|
EnableLevelSeparation bool `mapstructure:"enable_level_separation"`
|
||||||
|
LevelConfigs map[string]MuziLevelFileConfig `mapstructure:"level_configs"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// MuziLevelFileConfig 木子数据日志级别配置
|
||||||
|
type MuziLevelFileConfig struct {
|
||||||
|
MaxSize int `mapstructure:"max_size"`
|
||||||
|
MaxBackups int `mapstructure:"max_backups"`
|
||||||
|
MaxAge int `mapstructure:"max_age"`
|
||||||
|
Compress bool `mapstructure:"compress"`
|
||||||
|
}
|
||||||
|
|
||||||
// AliPayConfig 支付宝配置
|
// AliPayConfig 支付宝配置
|
||||||
type AliPayConfig struct {
|
type AliPayConfig struct {
|
||||||
AppID string `mapstructure:"app_id"`
|
AppID string `mapstructure:"app_id"`
|
||||||
@@ -451,10 +479,10 @@ type XingweiConfig struct {
|
|||||||
|
|
||||||
// XingweiLoggingConfig 行为数据日志配置
|
// XingweiLoggingConfig 行为数据日志配置
|
||||||
type XingweiLoggingConfig struct {
|
type XingweiLoggingConfig struct {
|
||||||
Enabled bool `mapstructure:"enabled"`
|
Enabled bool `mapstructure:"enabled"`
|
||||||
LogDir string `mapstructure:"log_dir"`
|
LogDir string `mapstructure:"log_dir"`
|
||||||
UseDaily bool `mapstructure:"use_daily"`
|
UseDaily bool `mapstructure:"use_daily"`
|
||||||
EnableLevelSeparation bool `mapstructure:"enable_level_separation"`
|
EnableLevelSeparation bool `mapstructure:"enable_level_separation"`
|
||||||
LevelConfigs map[string]XingweiLevelFileConfig `mapstructure:"level_configs"`
|
LevelConfigs map[string]XingweiLevelFileConfig `mapstructure:"level_configs"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ import (
|
|||||||
infra_events "tyapi-server/internal/infrastructure/events"
|
infra_events "tyapi-server/internal/infrastructure/events"
|
||||||
"tyapi-server/internal/infrastructure/external/alicloud"
|
"tyapi-server/internal/infrastructure/external/alicloud"
|
||||||
"tyapi-server/internal/infrastructure/external/email"
|
"tyapi-server/internal/infrastructure/external/email"
|
||||||
|
"tyapi-server/internal/infrastructure/external/muzi"
|
||||||
"tyapi-server/internal/infrastructure/external/ocr"
|
"tyapi-server/internal/infrastructure/external/ocr"
|
||||||
"tyapi-server/internal/infrastructure/external/sms"
|
"tyapi-server/internal/infrastructure/external/sms"
|
||||||
"tyapi-server/internal/infrastructure/external/storage"
|
"tyapi-server/internal/infrastructure/external/storage"
|
||||||
@@ -339,6 +340,10 @@ func NewContainer() *Container {
|
|||||||
func(cfg *config.Config) (*westdex.WestDexService, error) {
|
func(cfg *config.Config) (*westdex.WestDexService, error) {
|
||||||
return westdex.NewWestDexServiceWithConfig(cfg)
|
return westdex.NewWestDexServiceWithConfig(cfg)
|
||||||
},
|
},
|
||||||
|
// MuziService - 木子数据服务
|
||||||
|
func(cfg *config.Config) (*muzi.MuziService, error) {
|
||||||
|
return muzi.NewMuziServiceWithConfig(cfg)
|
||||||
|
},
|
||||||
// ZhichaService - 智查金控服务
|
// ZhichaService - 智查金控服务
|
||||||
func(cfg *config.Config) (*zhicha.ZhichaService, error) {
|
func(cfg *config.Config) (*zhicha.ZhichaService, error) {
|
||||||
return zhicha.NewZhichaServiceWithConfig(cfg)
|
return zhicha.NewZhichaServiceWithConfig(cfg)
|
||||||
@@ -401,9 +406,9 @@ func NewContainer() *Container {
|
|||||||
BlockedCountries: cfg.DailyRateLimit.BlockedCountries,
|
BlockedCountries: cfg.DailyRateLimit.BlockedCountries,
|
||||||
EnableProxyCheck: cfg.DailyRateLimit.EnableProxyCheck,
|
EnableProxyCheck: cfg.DailyRateLimit.EnableProxyCheck,
|
||||||
// 排除路径配置
|
// 排除路径配置
|
||||||
ExcludePaths: cfg.DailyRateLimit.ExcludePaths,
|
ExcludePaths: cfg.DailyRateLimit.ExcludePaths,
|
||||||
// 排除域名配置
|
// 排除域名配置
|
||||||
ExcludeDomains: cfg.DailyRateLimit.ExcludeDomains,
|
ExcludeDomains: cfg.DailyRateLimit.ExcludeDomains,
|
||||||
}
|
}
|
||||||
return middleware.NewDailyRateLimitMiddleware(cfg, redis, response, logger, limitConfig)
|
return middleware.NewDailyRateLimitMiddleware(cfg, redis, response, logger, limitConfig)
|
||||||
},
|
},
|
||||||
@@ -767,8 +772,8 @@ func NewContainer() *Container {
|
|||||||
},
|
},
|
||||||
// AsynqWorker - 任务处理器
|
// AsynqWorker - 任务处理器
|
||||||
func(
|
func(
|
||||||
cfg *config.Config,
|
cfg *config.Config,
|
||||||
logger *zap.Logger,
|
logger *zap.Logger,
|
||||||
articleApplicationService article.ArticleApplicationService,
|
articleApplicationService article.ArticleApplicationService,
|
||||||
apiApplicationService api_app.ApiApplicationService,
|
apiApplicationService api_app.ApiApplicationService,
|
||||||
walletService finance_services.WalletAggregateService,
|
walletService finance_services.WalletAggregateService,
|
||||||
@@ -777,8 +782,8 @@ func NewContainer() *Container {
|
|||||||
) *asynq.AsynqWorker {
|
) *asynq.AsynqWorker {
|
||||||
redisAddr := fmt.Sprintf("%s:%s", cfg.Redis.Host, cfg.Redis.Port)
|
redisAddr := fmt.Sprintf("%s:%s", cfg.Redis.Host, cfg.Redis.Port)
|
||||||
return asynq.NewAsynqWorker(
|
return asynq.NewAsynqWorker(
|
||||||
redisAddr,
|
redisAddr,
|
||||||
logger,
|
logger,
|
||||||
articleApplicationService,
|
articleApplicationService,
|
||||||
apiApplicationService,
|
apiApplicationService,
|
||||||
walletService,
|
walletService,
|
||||||
@@ -1076,12 +1081,12 @@ func RegisterLifecycleHooks(
|
|||||||
},
|
},
|
||||||
OnStop: func(context.Context) error {
|
OnStop: func(context.Context) error {
|
||||||
logger.Info("应用关闭中...")
|
logger.Info("应用关闭中...")
|
||||||
|
|
||||||
// 停止AsynqWorker
|
// 停止AsynqWorker
|
||||||
asynqWorker.Stop()
|
asynqWorker.Stop()
|
||||||
asynqWorker.Shutdown()
|
asynqWorker.Shutdown()
|
||||||
logger.Info("AsynqWorker已停止")
|
logger.Info("AsynqWorker已停止")
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -281,6 +281,11 @@ type IVYZ7F3AReq struct {
|
|||||||
Authorized string `json:"authorized" validate:"required,oneof=0 1"`
|
Authorized string `json:"authorized" validate:"required,oneof=0 1"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type IVYZ3P9MReq struct {
|
||||||
|
IDCard string `json:"id_card" validate:"required,validIDCard"`
|
||||||
|
Name string `json:"name" validate:"required,min=1,validName"`
|
||||||
|
}
|
||||||
|
|
||||||
type IVYZ3A7FReq struct {
|
type IVYZ3A7FReq 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"`
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import (
|
|||||||
"tyapi-server/internal/domains/api/services/processors/yysy"
|
"tyapi-server/internal/domains/api/services/processors/yysy"
|
||||||
"tyapi-server/internal/domains/product/services"
|
"tyapi-server/internal/domains/product/services"
|
||||||
"tyapi-server/internal/infrastructure/external/alicloud"
|
"tyapi-server/internal/infrastructure/external/alicloud"
|
||||||
|
"tyapi-server/internal/infrastructure/external/muzi"
|
||||||
"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/xingwei"
|
||||||
@@ -36,6 +37,7 @@ var (
|
|||||||
type ApiRequestService struct {
|
type ApiRequestService struct {
|
||||||
// 可注入依赖,如第三方服务、模型等
|
// 可注入依赖,如第三方服务、模型等
|
||||||
westDexService *westdex.WestDexService
|
westDexService *westdex.WestDexService
|
||||||
|
muziService *muzi.MuziService
|
||||||
yushanService *yushan.YushanService
|
yushanService *yushan.YushanService
|
||||||
tianYanChaService *tianyancha.TianYanChaService
|
tianYanChaService *tianyancha.TianYanChaService
|
||||||
alicloudService *alicloud.AlicloudService
|
alicloudService *alicloud.AlicloudService
|
||||||
@@ -46,6 +48,7 @@ type ApiRequestService struct {
|
|||||||
|
|
||||||
func NewApiRequestService(
|
func NewApiRequestService(
|
||||||
westDexService *westdex.WestDexService,
|
westDexService *westdex.WestDexService,
|
||||||
|
muziService *muzi.MuziService,
|
||||||
yushanService *yushan.YushanService,
|
yushanService *yushan.YushanService,
|
||||||
tianYanChaService *tianyancha.TianYanChaService,
|
tianYanChaService *tianyancha.TianYanChaService,
|
||||||
alicloudService *alicloud.AlicloudService,
|
alicloudService *alicloud.AlicloudService,
|
||||||
@@ -58,13 +61,14 @@ func NewApiRequestService(
|
|||||||
combService := comb.NewCombService(productManagementService)
|
combService := comb.NewCombService(productManagementService)
|
||||||
|
|
||||||
// 创建处理器依赖容器
|
// 创建处理器依赖容器
|
||||||
processorDeps := processors.NewProcessorDependencies(westDexService, yushanService, tianYanChaService, alicloudService, zhichaService, xingweiService, validator, combService)
|
processorDeps := processors.NewProcessorDependencies(westDexService, muziService, yushanService, tianYanChaService, alicloudService, zhichaService, xingweiService, validator, combService)
|
||||||
|
|
||||||
// 统一注册所有处理器
|
// 统一注册所有处理器
|
||||||
registerAllProcessors(combService)
|
registerAllProcessors(combService)
|
||||||
|
|
||||||
return &ApiRequestService{
|
return &ApiRequestService{
|
||||||
westDexService: westDexService,
|
westDexService: westDexService,
|
||||||
|
muziService: muziService,
|
||||||
yushanService: yushanService,
|
yushanService: yushanService,
|
||||||
tianYanChaService: tianYanChaService,
|
tianYanChaService: tianYanChaService,
|
||||||
alicloudService: alicloudService,
|
alicloudService: alicloudService,
|
||||||
@@ -155,7 +159,7 @@ func registerAllProcessors(combService *comb.CombService) {
|
|||||||
"YYSY8C2D": yysy.ProcessYYSY8C2DRequest,
|
"YYSY8C2D": yysy.ProcessYYSY8C2DRequest,
|
||||||
"YYSY7D3E": yysy.ProcessYYSY7D3ERequest,
|
"YYSY7D3E": yysy.ProcessYYSY7D3ERequest,
|
||||||
"YYSY9E4A": yysy.ProcessYYSY9E4ARequest,
|
"YYSY9E4A": yysy.ProcessYYSY9E4ARequest,
|
||||||
|
|
||||||
// IVYZ系列处理器
|
// IVYZ系列处理器
|
||||||
"IVYZ0B03": ivyz.ProcessIVYZ0B03Request,
|
"IVYZ0B03": ivyz.ProcessIVYZ0B03Request,
|
||||||
"IVYZ2125": ivyz.ProcessIVYZ2125Request,
|
"IVYZ2125": ivyz.ProcessIVYZ2125Request,
|
||||||
@@ -172,12 +176,13 @@ func registerAllProcessors(combService *comb.CombService) {
|
|||||||
"IVYZ7C9D": ivyz.ProcessIVYZ7C9DRequest,
|
"IVYZ7C9D": ivyz.ProcessIVYZ7C9DRequest,
|
||||||
"IVYZ5E3F": ivyz.ProcessIVYZ5E3FRequest,
|
"IVYZ5E3F": ivyz.ProcessIVYZ5E3FRequest,
|
||||||
"IVYZ7F3A": ivyz.ProcessIVYZ7F3ARequest,
|
"IVYZ7F3A": ivyz.ProcessIVYZ7F3ARequest,
|
||||||
|
"IVYZ3P9M": ivyz.ProcessIVYZ3P9MRequest,
|
||||||
"IVYZ3A7F": ivyz.ProcessIVYZ3A7FRequest,
|
"IVYZ3A7F": ivyz.ProcessIVYZ3A7FRequest,
|
||||||
"IVYZ9D2E": ivyz.ProcessIVYZ9D2ERequest,
|
"IVYZ9D2E": ivyz.ProcessIVYZ9D2ERequest,
|
||||||
"IVYZ81NC": ivyz.ProcessIVYZ81NCRequest,
|
"IVYZ81NC": ivyz.ProcessIVYZ81NCRequest,
|
||||||
"IVYZ6G7H": ivyz.ProcessIVYZ6G7HRequest,
|
"IVYZ6G7H": ivyz.ProcessIVYZ6G7HRequest,
|
||||||
"IVYZ8I9J": ivyz.ProcessIVYZ8I9JRequest,
|
"IVYZ8I9J": ivyz.ProcessIVYZ8I9JRequest,
|
||||||
|
|
||||||
// COMB系列处理器 - 只注册有自定义逻辑的组合包
|
// COMB系列处理器 - 只注册有自定义逻辑的组合包
|
||||||
"COMB86PM": comb.ProcessCOMB86PMRequest, // 有自定义逻辑:重命名ApiCode
|
"COMB86PM": comb.ProcessCOMB86PMRequest, // 有自定义逻辑:重命名ApiCode
|
||||||
|
|
||||||
@@ -215,17 +220,17 @@ var RequestProcessors map[string]processors.ProcessorFunc
|
|||||||
func (a *ApiRequestService) PreprocessRequestApi(ctx context.Context, apiCode string, params []byte, options *commands.ApiCallOptions, callContext *processors.CallContext) ([]byte, error) {
|
func (a *ApiRequestService) PreprocessRequestApi(ctx context.Context, apiCode string, params []byte, options *commands.ApiCallOptions, callContext *processors.CallContext) ([]byte, error) {
|
||||||
// 设置Options和CallContext到依赖容器
|
// 设置Options和CallContext到依赖容器
|
||||||
deps := a.processorDeps.WithOptions(options).WithCallContext(callContext)
|
deps := a.processorDeps.WithOptions(options).WithCallContext(callContext)
|
||||||
|
|
||||||
// 1. 优先查找已注册的自定义处理器
|
// 1. 优先查找已注册的自定义处理器
|
||||||
if processor, exists := RequestProcessors[apiCode]; exists {
|
if processor, exists := RequestProcessors[apiCode]; exists {
|
||||||
return processor(ctx, params, deps)
|
return processor(ctx, params, deps)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. 检查是否为组合包(COMB开头),使用通用组合包处理器
|
// 2. 检查是否为组合包(COMB开头),使用通用组合包处理器
|
||||||
if len(apiCode) >= 4 && apiCode[:4] == "COMB" {
|
if len(apiCode) >= 4 && apiCode[:4] == "COMB" {
|
||||||
return a.processGenericCombRequest(ctx, apiCode, params, deps)
|
return a.processGenericCombRequest(ctx, apiCode, params, deps)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, fmt.Errorf("%s: 未找到处理器: %s", ErrSystem, apiCode)
|
return nil, fmt.Errorf("%s: 未找到处理器: %s", ErrSystem, apiCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -237,7 +242,7 @@ func (a *ApiRequestService) processGenericCombRequest(ctx context.Context, apiCo
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// 直接返回组合结果,无任何自定义处理
|
// 直接返回组合结果,无任何自定义处理
|
||||||
return json.Marshal(combinedResult)
|
return json.Marshal(combinedResult)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -152,6 +152,7 @@ func (s *FormConfigServiceImpl) getDTOStruct(ctx context.Context, apiCode string
|
|||||||
"FLXG8B4D": &dto.FLXG8B4DReq{},
|
"FLXG8B4D": &dto.FLXG8B4DReq{},
|
||||||
"IVYZ81NC": &dto.IVYZ81NCReq{},
|
"IVYZ81NC": &dto.IVYZ81NCReq{},
|
||||||
"IVYZ7F3A": &dto.IVYZ7F3AReq{},
|
"IVYZ7F3A": &dto.IVYZ7F3AReq{},
|
||||||
|
"IVYZ3P9M": &dto.IVYZ3P9MReq{},
|
||||||
"IVYZ3A7F": &dto.IVYZ3A7FReq{},
|
"IVYZ3A7F": &dto.IVYZ3A7FReq{},
|
||||||
"IVYZ9D2E": &dto.IVYZ9D2EReq{},
|
"IVYZ9D2E": &dto.IVYZ9D2EReq{},
|
||||||
"DWBG7F3A": &dto.DWBG7F3AReq{},
|
"DWBG7F3A": &dto.DWBG7F3AReq{},
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"tyapi-server/internal/application/api/commands"
|
"tyapi-server/internal/application/api/commands"
|
||||||
"tyapi-server/internal/infrastructure/external/alicloud"
|
"tyapi-server/internal/infrastructure/external/alicloud"
|
||||||
|
"tyapi-server/internal/infrastructure/external/muzi"
|
||||||
"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/xingwei"
|
||||||
@@ -25,20 +26,22 @@ type CallContext struct {
|
|||||||
// ProcessorDependencies 处理器依赖容器
|
// ProcessorDependencies 处理器依赖容器
|
||||||
type ProcessorDependencies struct {
|
type ProcessorDependencies struct {
|
||||||
WestDexService *westdex.WestDexService
|
WestDexService *westdex.WestDexService
|
||||||
|
MuziService *muzi.MuziService
|
||||||
YushanService *yushan.YushanService
|
YushanService *yushan.YushanService
|
||||||
TianYanChaService *tianyancha.TianYanChaService
|
TianYanChaService *tianyancha.TianYanChaService
|
||||||
AlicloudService *alicloud.AlicloudService
|
AlicloudService *alicloud.AlicloudService
|
||||||
ZhichaService *zhicha.ZhichaService
|
ZhichaService *zhicha.ZhichaService
|
||||||
XingweiService *xingwei.XingweiService
|
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支持
|
||||||
CallContext *CallContext // 添加CallApi调用上下文
|
CallContext *CallContext // 添加CallApi调用上下文
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewProcessorDependencies 创建处理器依赖容器
|
// NewProcessorDependencies 创建处理器依赖容器
|
||||||
func NewProcessorDependencies(
|
func NewProcessorDependencies(
|
||||||
westDexService *westdex.WestDexService,
|
westDexService *westdex.WestDexService,
|
||||||
|
muziService *muzi.MuziService,
|
||||||
yushanService *yushan.YushanService,
|
yushanService *yushan.YushanService,
|
||||||
tianYanChaService *tianyancha.TianYanChaService,
|
tianYanChaService *tianyancha.TianYanChaService,
|
||||||
alicloudService *alicloud.AlicloudService,
|
alicloudService *alicloud.AlicloudService,
|
||||||
@@ -49,6 +52,7 @@ func NewProcessorDependencies(
|
|||||||
) *ProcessorDependencies {
|
) *ProcessorDependencies {
|
||||||
return &ProcessorDependencies{
|
return &ProcessorDependencies{
|
||||||
WestDexService: westDexService,
|
WestDexService: westDexService,
|
||||||
|
MuziService: muziService,
|
||||||
YushanService: yushanService,
|
YushanService: yushanService,
|
||||||
TianYanChaService: tianYanChaService,
|
TianYanChaService: tianYanChaService,
|
||||||
AlicloudService: alicloudService,
|
AlicloudService: alicloudService,
|
||||||
@@ -74,9 +78,7 @@ func (deps *ProcessorDependencies) WithCallContext(callContext *CallContext) *Pr
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ProcessorFunc 处理器函数类型定义
|
// ProcessorFunc 处理器函数类型定义
|
||||||
type ProcessorFunc func(ctx context.Context, params []byte, deps *ProcessorDependencies) ([]byte, error)
|
type ProcessorFunc func(ctx context.Context, params []byte, deps *ProcessorDependencies) ([]byte, error)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// CombinedResult 组合结果
|
// CombinedResult 组合结果
|
||||||
type CombinedResult struct {
|
type CombinedResult struct {
|
||||||
@@ -91,4 +93,3 @@ type SubProductResult struct {
|
|||||||
Error string `json:"error,omitempty"` // 错误信息(仅在失败时)
|
Error string `json:"error,omitempty"` // 错误信息(仅在失败时)
|
||||||
SortOrder int `json:"-"` // 排序字段,不输出到JSON
|
SortOrder int `json:"-"` // 排序字段,不输出到JSON
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,52 @@
|
|||||||
|
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/muzi"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ProcessIVYZ3P9MRequest IVYZ3P9M API处理方法 - 学历查询实时版
|
||||||
|
func ProcessIVYZ3P9MRequest(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
|
||||||
|
var paramsDto dto.IVYZ3P9MReq
|
||||||
|
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.MuziService.Encrypt(paramsDto.Name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Join(processors.ErrSystem, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
encryptedCertCode, err := deps.MuziService.Encrypt(paramsDto.IDCard)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Join(processors.ErrSystem, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
reqData := map[string]interface{}{
|
||||||
|
"realName": encryptedName,
|
||||||
|
"certCode": encryptedCertCode,
|
||||||
|
}
|
||||||
|
|
||||||
|
respData, err := deps.MuziService.CallAPI(ctx, "PC0041", reqData)
|
||||||
|
if err != nil {
|
||||||
|
switch {
|
||||||
|
case errors.Is(err, muzi.ErrDatasource):
|
||||||
|
return nil, errors.Join(processors.ErrDatasource, err)
|
||||||
|
case errors.Is(err, muzi.ErrSystem):
|
||||||
|
return nil, errors.Join(processors.ErrSystem, err)
|
||||||
|
default:
|
||||||
|
return nil, errors.Join(processors.ErrSystem, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return respData, nil
|
||||||
|
}
|
||||||
25
internal/infrastructure/external/muzi/muzi_errors.go
vendored
Normal file
25
internal/infrastructure/external/muzi/muzi_errors.go
vendored
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
package muzi
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
// MuziError 木子数据业务错误
|
||||||
|
type MuziError struct {
|
||||||
|
Code int
|
||||||
|
Message string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error implements error interface.
|
||||||
|
func (e *MuziError) Error() string {
|
||||||
|
return fmt.Sprintf("木子数据返回错误,代码: %d,信息: %s", e.Code, e.Message)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewMuziError 根据错误码创建业务错误
|
||||||
|
func NewMuziError(code int, message string) *MuziError {
|
||||||
|
if message == "" {
|
||||||
|
message = "木子数据返回未知错误"
|
||||||
|
}
|
||||||
|
return &MuziError{
|
||||||
|
Code: code,
|
||||||
|
Message: message,
|
||||||
|
}
|
||||||
|
}
|
||||||
61
internal/infrastructure/external/muzi/muzi_factory.go
vendored
Normal file
61
internal/infrastructure/external/muzi/muzi_factory.go
vendored
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
package muzi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"tyapi-server/internal/config"
|
||||||
|
"tyapi-server/internal/shared/external_logger"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewMuziServiceWithConfig 使用配置创建木子数据服务
|
||||||
|
func NewMuziServiceWithConfig(cfg *config.Config) (*MuziService, error) {
|
||||||
|
loggingConfig := external_logger.ExternalServiceLoggingConfig{
|
||||||
|
Enabled: cfg.Muzi.Logging.Enabled,
|
||||||
|
LogDir: cfg.Muzi.Logging.LogDir,
|
||||||
|
ServiceName: "muzi",
|
||||||
|
UseDaily: cfg.Muzi.Logging.UseDaily,
|
||||||
|
EnableLevelSeparation: cfg.Muzi.Logging.EnableLevelSeparation,
|
||||||
|
LevelConfigs: make(map[string]external_logger.ExternalServiceLevelFileConfig),
|
||||||
|
}
|
||||||
|
|
||||||
|
for level, levelCfg := range cfg.Muzi.Logging.LevelConfigs {
|
||||||
|
loggingConfig.LevelConfigs[level] = external_logger.ExternalServiceLevelFileConfig{
|
||||||
|
MaxSize: levelCfg.MaxSize,
|
||||||
|
MaxBackups: levelCfg.MaxBackups,
|
||||||
|
MaxAge: levelCfg.MaxAge,
|
||||||
|
Compress: levelCfg.Compress,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
logger, err := external_logger.NewExternalServiceLogger(loggingConfig)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
service := NewMuziService(
|
||||||
|
cfg.Muzi.URL,
|
||||||
|
cfg.Muzi.AppID,
|
||||||
|
cfg.Muzi.AppSecret,
|
||||||
|
cfg.Muzi.Timeout,
|
||||||
|
logger,
|
||||||
|
)
|
||||||
|
|
||||||
|
return service, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewMuziServiceWithLogging 使用自定义日志配置创建木子数据服务
|
||||||
|
func NewMuziServiceWithLogging(url, appID, appSecret string, timeout time.Duration, loggingConfig external_logger.ExternalServiceLoggingConfig) (*MuziService, error) {
|
||||||
|
loggingConfig.ServiceName = "muzi"
|
||||||
|
|
||||||
|
logger, err := external_logger.NewExternalServiceLogger(loggingConfig)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return NewMuziService(url, appID, appSecret, timeout, logger), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewMuziServiceSimple 创建无日志的木子数据服务
|
||||||
|
func NewMuziServiceSimple(url, appID, appSecret string, timeout time.Duration) *MuziService {
|
||||||
|
return NewMuziService(url, appID, appSecret, timeout, nil)
|
||||||
|
}
|
||||||
389
internal/infrastructure/external/muzi/muzi_service.go
vendored
Normal file
389
internal/infrastructure/external/muzi/muzi_service.go
vendored
Normal file
@@ -0,0 +1,389 @@
|
|||||||
|
package muzi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"crypto/aes"
|
||||||
|
"crypto/md5"
|
||||||
|
"encoding/base64"
|
||||||
|
"encoding/hex"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"reflect"
|
||||||
|
"sort"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"tyapi-server/internal/shared/external_logger"
|
||||||
|
)
|
||||||
|
|
||||||
|
const defaultRequestTimeout = 60 * time.Second
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrDatasource = errors.New("数据源异常")
|
||||||
|
ErrSystem = errors.New("系统异常")
|
||||||
|
)
|
||||||
|
|
||||||
|
// Muzi状态码常量
|
||||||
|
const (
|
||||||
|
CodeSuccess = 0 // 成功查询
|
||||||
|
CodeSystemError = 500 // 系统异常
|
||||||
|
CodeParamMissing = 601 // 参数不全
|
||||||
|
CodeInterfaceExpired = 602 // 接口已过期
|
||||||
|
CodeVerifyFailed = 603 // 接口校验失败
|
||||||
|
CodeIPNotInWhitelist = 604 // IP不在白名单中
|
||||||
|
CodeProductNotFound = 701 // 产品编号不存在
|
||||||
|
CodeUserNotFound = 702 // 用户名不存在
|
||||||
|
CodeUnauthorizedAPI = 703 // 接口未授权
|
||||||
|
CodeInsufficientFund = 704 // 商户余额不足
|
||||||
|
)
|
||||||
|
|
||||||
|
// MuziResponse 木子数据接口通用响应
|
||||||
|
type MuziResponse struct {
|
||||||
|
Code int `json:"code"`
|
||||||
|
Msg string `json:"msg"`
|
||||||
|
Data json.RawMessage `json:"data"`
|
||||||
|
Timestamp int64 `json:"timestamp"`
|
||||||
|
ExecuteTime int64 `json:"executeTime"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// MuziConfig 木子数据接口配置
|
||||||
|
type MuziConfig struct {
|
||||||
|
URL string
|
||||||
|
AppID string
|
||||||
|
AppSecret string
|
||||||
|
Timeout time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
// MuziService 木子数据接口服务封装
|
||||||
|
type MuziService struct {
|
||||||
|
config MuziConfig
|
||||||
|
logger *external_logger.ExternalServiceLogger
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewMuziService 创建木子数据服务实例
|
||||||
|
func NewMuziService(url, appID, appSecret string, timeout time.Duration, logger *external_logger.ExternalServiceLogger) *MuziService {
|
||||||
|
if timeout <= 0 {
|
||||||
|
timeout = defaultRequestTimeout
|
||||||
|
}
|
||||||
|
|
||||||
|
return &MuziService{
|
||||||
|
config: MuziConfig{
|
||||||
|
URL: url,
|
||||||
|
AppID: appID,
|
||||||
|
AppSecret: appSecret,
|
||||||
|
Timeout: timeout,
|
||||||
|
},
|
||||||
|
logger: logger,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// generateRequestID 生成请求ID
|
||||||
|
func (m *MuziService) generateRequestID() string {
|
||||||
|
timestamp := time.Now().UnixNano()
|
||||||
|
raw := fmt.Sprintf("%d_%s", timestamp, m.config.AppID)
|
||||||
|
sum := md5.Sum([]byte(raw))
|
||||||
|
return fmt.Sprintf("muzi_%x", sum[:8])
|
||||||
|
}
|
||||||
|
|
||||||
|
// CallAPI 调用木子数据接口
|
||||||
|
func (m *MuziService) CallAPI(ctx context.Context, prodCode string, params map[string]interface{}) (json.RawMessage, error) {
|
||||||
|
requestID := m.generateRequestID()
|
||||||
|
now := time.Now()
|
||||||
|
timestamp := strconv.FormatInt(now.UnixMilli(), 10)
|
||||||
|
|
||||||
|
flatParams := flattenParams(params)
|
||||||
|
signParts := collectSignatureValues(params)
|
||||||
|
signature := m.GenerateSignature(prodCode, timestamp, signParts...)
|
||||||
|
|
||||||
|
// 从上下文获取链路ID
|
||||||
|
var transactionID string
|
||||||
|
if ctxTransactionID, ok := ctx.Value("transaction_id").(string); ok {
|
||||||
|
transactionID = ctxTransactionID
|
||||||
|
}
|
||||||
|
|
||||||
|
requestBody := map[string]interface{}{
|
||||||
|
"appId": m.config.AppID,
|
||||||
|
"prodCode": prodCode,
|
||||||
|
"timestamp": timestamp,
|
||||||
|
"signature": signature,
|
||||||
|
}
|
||||||
|
for key, value := range flatParams {
|
||||||
|
requestBody[key] = value
|
||||||
|
}
|
||||||
|
|
||||||
|
if m.logger != nil {
|
||||||
|
m.logger.LogRequest(requestID, transactionID, prodCode, m.config.URL, requestBody)
|
||||||
|
}
|
||||||
|
|
||||||
|
bodyBytes, marshalErr := json.Marshal(requestBody)
|
||||||
|
if marshalErr != nil {
|
||||||
|
err := errors.Join(ErrSystem, marshalErr)
|
||||||
|
if m.logger != nil {
|
||||||
|
m.logger.LogError(requestID, transactionID, prodCode, err, requestBody)
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
req, reqErr := http.NewRequestWithContext(ctx, http.MethodPost, m.config.URL, bytes.NewBuffer(bodyBytes))
|
||||||
|
if reqErr != nil {
|
||||||
|
err := errors.Join(ErrSystem, reqErr)
|
||||||
|
if m.logger != nil {
|
||||||
|
m.logger.LogError(requestID, transactionID, prodCode, err, requestBody)
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
req.Header.Set("Content-Type", "application/json")
|
||||||
|
|
||||||
|
client := &http.Client{
|
||||||
|
Timeout: m.config.Timeout,
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, httpErr := client.Do(req)
|
||||||
|
if httpErr != nil {
|
||||||
|
err := wrapHTTPError(httpErr)
|
||||||
|
if errors.Is(err, ErrDatasource) {
|
||||||
|
err = errors.Join(err, fmt.Errorf("API请求超时: %v", httpErr))
|
||||||
|
}
|
||||||
|
if m.logger != nil {
|
||||||
|
m.logger.LogError(requestID, transactionID, prodCode, err, requestBody)
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer func(body io.ReadCloser) {
|
||||||
|
closeErr := body.Close()
|
||||||
|
if closeErr != nil && m.logger != nil {
|
||||||
|
m.logger.LogError(requestID, transactionID, prodCode, errors.Join(ErrSystem, fmt.Errorf("关闭响应体失败: %w", closeErr)), requestBody)
|
||||||
|
}
|
||||||
|
}(resp.Body)
|
||||||
|
|
||||||
|
respBody, readErr := io.ReadAll(resp.Body)
|
||||||
|
if readErr != nil {
|
||||||
|
err := errors.Join(ErrSystem, readErr)
|
||||||
|
if m.logger != nil {
|
||||||
|
m.logger.LogError(requestID, transactionID, prodCode, err, requestBody)
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if m.logger != nil {
|
||||||
|
m.logger.LogResponse(requestID, transactionID, prodCode, resp.StatusCode, respBody, time.Since(now))
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.StatusCode != http.StatusOK {
|
||||||
|
err := errors.Join(ErrDatasource, fmt.Errorf("HTTP状态码 %d", resp.StatusCode))
|
||||||
|
if m.logger != nil {
|
||||||
|
m.logger.LogError(requestID, transactionID, prodCode, err, requestBody)
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var muziResp MuziResponse
|
||||||
|
if err := json.Unmarshal(respBody, &muziResp); err != nil {
|
||||||
|
err = errors.Join(ErrSystem, fmt.Errorf("响应解析失败: %v", err))
|
||||||
|
if m.logger != nil {
|
||||||
|
m.logger.LogError(requestID, transactionID, prodCode, err, requestBody)
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if muziResp.Code != CodeSuccess {
|
||||||
|
muziErr := NewMuziError(muziResp.Code, muziResp.Msg)
|
||||||
|
var resultErr error
|
||||||
|
|
||||||
|
switch muziResp.Code {
|
||||||
|
case CodeSystemError:
|
||||||
|
resultErr = errors.Join(ErrDatasource, muziErr)
|
||||||
|
default:
|
||||||
|
resultErr = errors.Join(ErrSystem, muziErr)
|
||||||
|
}
|
||||||
|
|
||||||
|
if m.logger != nil {
|
||||||
|
m.logger.LogError(requestID, transactionID, prodCode, muziErr, requestBody)
|
||||||
|
}
|
||||||
|
return nil, resultErr
|
||||||
|
}
|
||||||
|
|
||||||
|
return muziResp.Data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func wrapHTTPError(err error) error {
|
||||||
|
var timeout bool
|
||||||
|
if err == context.DeadlineExceeded {
|
||||||
|
timeout = true
|
||||||
|
} else if netErr, ok := err.(interface{ Timeout() bool }); ok && netErr.Timeout() {
|
||||||
|
timeout = true
|
||||||
|
} else if errStr := err.Error(); errStr == "context deadline exceeded" ||
|
||||||
|
errStr == "timeout" ||
|
||||||
|
errStr == "Client.Timeout exceeded" ||
|
||||||
|
errStr == "net/http: request canceled" {
|
||||||
|
timeout = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if timeout {
|
||||||
|
return errors.Join(ErrDatasource, err)
|
||||||
|
}
|
||||||
|
return errors.Join(ErrSystem, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func pkcs5Padding(src []byte, blockSize int) []byte {
|
||||||
|
padding := blockSize - len(src)%blockSize
|
||||||
|
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
|
||||||
|
return append(src, padtext...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func flattenParams(params map[string]interface{}) map[string]interface{} {
|
||||||
|
result := make(map[string]interface{})
|
||||||
|
if params == nil {
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
for key, value := range params {
|
||||||
|
flattenValue(key, value, result)
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func flattenValue(prefix string, value interface{}, out map[string]interface{}) {
|
||||||
|
switch val := value.(type) {
|
||||||
|
case map[string]interface{}:
|
||||||
|
for k, v := range val {
|
||||||
|
flattenValue(combinePrefix(prefix, k), v, out)
|
||||||
|
}
|
||||||
|
case map[interface{}]interface{}:
|
||||||
|
for k, v := range val {
|
||||||
|
keyStr := fmt.Sprint(k)
|
||||||
|
flattenValue(combinePrefix(prefix, keyStr), v, out)
|
||||||
|
}
|
||||||
|
case []interface{}:
|
||||||
|
for i, item := range val {
|
||||||
|
nextPrefix := fmt.Sprintf("%s[%d]", prefix, i)
|
||||||
|
flattenValue(nextPrefix, item, out)
|
||||||
|
}
|
||||||
|
case []string:
|
||||||
|
for i, item := range val {
|
||||||
|
nextPrefix := fmt.Sprintf("%s[%d]", prefix, i)
|
||||||
|
flattenValue(nextPrefix, item, out)
|
||||||
|
}
|
||||||
|
case []int:
|
||||||
|
for i, item := range val {
|
||||||
|
nextPrefix := fmt.Sprintf("%s[%d]", prefix, i)
|
||||||
|
flattenValue(nextPrefix, item, out)
|
||||||
|
}
|
||||||
|
case []float64:
|
||||||
|
for i, item := range val {
|
||||||
|
nextPrefix := fmt.Sprintf("%s[%d]", prefix, i)
|
||||||
|
flattenValue(nextPrefix, item, out)
|
||||||
|
}
|
||||||
|
case []bool:
|
||||||
|
for i, item := range val {
|
||||||
|
nextPrefix := fmt.Sprintf("%s[%d]", prefix, i)
|
||||||
|
flattenValue(nextPrefix, item, out)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
out[prefix] = val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func combinePrefix(prefix, key string) string {
|
||||||
|
if prefix == "" {
|
||||||
|
return key
|
||||||
|
}
|
||||||
|
return prefix + "." + key
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encrypt 使用 AES/ECB/PKCS5Padding 对单个字符串进行加密并返回 Base64 结果
|
||||||
|
func (m *MuziService) Encrypt(value string) (string, error) {
|
||||||
|
if len(m.config.AppSecret) != 32 {
|
||||||
|
return "", fmt.Errorf("AppSecret长度必须为32位")
|
||||||
|
}
|
||||||
|
|
||||||
|
block, err := aes.NewCipher([]byte(m.config.AppSecret))
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("初始化加密器失败: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
padded := pkcs5Padding([]byte(value), block.BlockSize())
|
||||||
|
encrypted := make([]byte, len(padded))
|
||||||
|
|
||||||
|
for bs, be := 0, block.BlockSize(); bs < len(padded); bs, be = bs+block.BlockSize(), be+block.BlockSize() {
|
||||||
|
block.Encrypt(encrypted[bs:be], padded[bs:be])
|
||||||
|
}
|
||||||
|
|
||||||
|
return base64.StdEncoding.EncodeToString(encrypted), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GenerateSignature 根据协议生成签名,extraValues 会按顺序追加在待签名字符串之后
|
||||||
|
func (m *MuziService) GenerateSignature(prodCode, timestamp string, extraValues ...string) string {
|
||||||
|
signStr := m.config.AppID + prodCode + timestamp
|
||||||
|
for _, extra := range extraValues {
|
||||||
|
signStr += extra
|
||||||
|
}
|
||||||
|
hash := md5.Sum([]byte(signStr))
|
||||||
|
return hex.EncodeToString(hash[:])
|
||||||
|
}
|
||||||
|
|
||||||
|
// GenerateTimestamp 生成当前毫秒级时间戳字符串
|
||||||
|
func (m *MuziService) GenerateTimestamp() string {
|
||||||
|
return strconv.FormatInt(time.Now().UnixMilli(), 10)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FlattenParams 将嵌套参数展平为一维键值对
|
||||||
|
func (m *MuziService) FlattenParams(params map[string]interface{}) map[string]interface{} {
|
||||||
|
return flattenParams(params)
|
||||||
|
}
|
||||||
|
|
||||||
|
func collectSignatureValues(data interface{}) []string {
|
||||||
|
var result []string
|
||||||
|
collectSignatureValuesRecursive(reflect.ValueOf(data), &result)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func collectSignatureValuesRecursive(value reflect.Value, result *[]string) {
|
||||||
|
if !value.IsValid() {
|
||||||
|
*result = append(*result, "")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
switch value.Kind() {
|
||||||
|
case reflect.Pointer, reflect.Interface:
|
||||||
|
if value.IsNil() {
|
||||||
|
*result = append(*result, "")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
collectSignatureValuesRecursive(value.Elem(), result)
|
||||||
|
case reflect.Map:
|
||||||
|
keys := value.MapKeys()
|
||||||
|
sort.Slice(keys, func(i, j int) bool {
|
||||||
|
return fmt.Sprint(keys[i].Interface()) < fmt.Sprint(keys[j].Interface())
|
||||||
|
})
|
||||||
|
for _, key := range keys {
|
||||||
|
collectSignatureValuesRecursive(value.MapIndex(key), result)
|
||||||
|
}
|
||||||
|
case reflect.Slice, reflect.Array:
|
||||||
|
for i := 0; i < value.Len(); i++ {
|
||||||
|
collectSignatureValuesRecursive(value.Index(i), result)
|
||||||
|
}
|
||||||
|
case reflect.Struct:
|
||||||
|
typeInfo := value.Type()
|
||||||
|
fieldNames := make([]string, 0, value.NumField())
|
||||||
|
fieldIndices := make(map[string]int, value.NumField())
|
||||||
|
for i := 0; i < value.NumField(); i++ {
|
||||||
|
field := typeInfo.Field(i)
|
||||||
|
if field.PkgPath != "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
fieldNames = append(fieldNames, field.Name)
|
||||||
|
fieldIndices[field.Name] = i
|
||||||
|
}
|
||||||
|
sort.Strings(fieldNames)
|
||||||
|
for _, name := range fieldNames {
|
||||||
|
collectSignatureValuesRecursive(value.Field(fieldIndices[name]), result)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
*result = append(*result, fmt.Sprint(value.Interface()))
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -18,23 +18,23 @@ import (
|
|||||||
|
|
||||||
// 行为数据API状态码常量
|
// 行为数据API状态码常量
|
||||||
const (
|
const (
|
||||||
CodeSuccess = 200 // 操作成功
|
CodeSuccess = 200 // 操作成功
|
||||||
CodeSystemError = 500 // 系统内部错误
|
CodeSystemError = 500 // 系统内部错误
|
||||||
CodeMerchantError = 3001 // 商家相关报错(商家不存在、商家被禁用、商家余额不足)
|
CodeMerchantError = 3001 // 商家相关报错(商家不存在、商家被禁用、商家余额不足)
|
||||||
CodeAccountExpired = 3002 // 账户已过期
|
CodeAccountExpired = 3002 // 账户已过期
|
||||||
CodeIPWhitelistMissing = 3003 // 未添加ip白名单
|
CodeIPWhitelistMissing = 3003 // 未添加ip白名单
|
||||||
CodeUnauthorized = 3004 // 未授权调用该接口
|
CodeUnauthorized = 3004 // 未授权调用该接口
|
||||||
CodeProductIDError = 4001 // 产品id错误
|
CodeProductIDError = 4001 // 产品id错误
|
||||||
CodeInterfaceDisabled = 4002 // 接口被停用
|
CodeInterfaceDisabled = 4002 // 接口被停用
|
||||||
CodeQueryException = 5001 // 接口查询异常,请联系技术人员
|
CodeQueryException = 5001 // 接口查询异常,请联系技术人员
|
||||||
CodeNotFound = 6000 // 未查询到结果
|
CodeNotFound = 6000 // 未查询到结果
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ErrDatasource = errors.New("数据源异常")
|
ErrDatasource = errors.New("数据源异常")
|
||||||
ErrSystem = errors.New("系统异常")
|
ErrSystem = errors.New("系统异常")
|
||||||
ErrNotFound = errors.New("未查询到结果")
|
ErrNotFound = errors.New("未查询到结果")
|
||||||
|
|
||||||
// 请求ID计数器,确保唯一性
|
// 请求ID计数器,确保唯一性
|
||||||
requestIDCounter int64
|
requestIDCounter int64
|
||||||
)
|
)
|
||||||
@@ -54,16 +54,16 @@ type XingweiErrorCode struct {
|
|||||||
|
|
||||||
// 行为数据错误码映射
|
// 行为数据错误码映射
|
||||||
var XingweiErrorCodes = map[int]XingweiErrorCode{
|
var XingweiErrorCodes = map[int]XingweiErrorCode{
|
||||||
CodeSuccess: {Code: CodeSuccess, Message: "操作成功"},
|
CodeSuccess: {Code: CodeSuccess, Message: "操作成功"},
|
||||||
CodeSystemError: {Code: CodeSystemError, Message: "系统内部错误"},
|
CodeSystemError: {Code: CodeSystemError, Message: "系统内部错误"},
|
||||||
CodeMerchantError: {Code: CodeMerchantError, Message: "商家相关报错(商家不存在、商家被禁用、商家余额不足)"},
|
CodeMerchantError: {Code: CodeMerchantError, Message: "商家相关报错(商家不存在、商家被禁用、商家余额不足)"},
|
||||||
CodeAccountExpired: {Code: CodeAccountExpired, Message: "账户已过期"},
|
CodeAccountExpired: {Code: CodeAccountExpired, Message: "账户已过期"},
|
||||||
CodeIPWhitelistMissing: {Code: CodeIPWhitelistMissing, Message: "未添加ip白名单"},
|
CodeIPWhitelistMissing: {Code: CodeIPWhitelistMissing, Message: "未添加ip白名单"},
|
||||||
CodeUnauthorized: {Code: CodeUnauthorized, Message: "未授权调用该接口"},
|
CodeUnauthorized: {Code: CodeUnauthorized, Message: "未授权调用该接口"},
|
||||||
CodeProductIDError: {Code: CodeProductIDError, Message: "产品id错误"},
|
CodeProductIDError: {Code: CodeProductIDError, Message: "产品id错误"},
|
||||||
CodeInterfaceDisabled: {Code: CodeInterfaceDisabled, Message: "接口被停用"},
|
CodeInterfaceDisabled: {Code: CodeInterfaceDisabled, Message: "接口被停用"},
|
||||||
CodeQueryException: {Code: CodeQueryException, Message: "接口查询异常,请联系技术人员"},
|
CodeQueryException: {Code: CodeQueryException, Message: "接口查询异常,请联系技术人员"},
|
||||||
CodeNotFound: {Code: CodeNotFound, Message: "未查询到结果"},
|
CodeNotFound: {Code: CodeNotFound, Message: "未查询到结果"},
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetXingweiErrorMessage 根据错误码获取错误消息
|
// GetXingweiErrorMessage 根据错误码获取错误消息
|
||||||
@@ -172,14 +172,13 @@ func (x *XingweiService) CallAPI(ctx context.Context, projectID string, params m
|
|||||||
isTimeout = true
|
isTimeout = true
|
||||||
} else if netErr, ok := clientDoErr.(interface{ Timeout() bool }); ok && netErr.Timeout() {
|
} else if netErr, ok := clientDoErr.(interface{ Timeout() bool }); ok && netErr.Timeout() {
|
||||||
isTimeout = true
|
isTimeout = true
|
||||||
} else if errStr := clientDoErr.Error();
|
} else if errStr := clientDoErr.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" {
|
|
||||||
isTimeout = true
|
isTimeout = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if isTimeout {
|
if isTimeout {
|
||||||
err = errors.Join(ErrDatasource, fmt.Errorf("API请求超时: %v", clientDoErr))
|
err = errors.Join(ErrDatasource, fmt.Errorf("API请求超时: %v", clientDoErr))
|
||||||
} else {
|
} else {
|
||||||
@@ -244,7 +243,7 @@ func (x *XingweiService) CallAPI(ctx context.Context, projectID string, params m
|
|||||||
if xingweiResp.Data == nil {
|
if xingweiResp.Data == nil {
|
||||||
return []byte("{}"), nil
|
return []byte("{}"), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// 将data转换为JSON字节
|
// 将data转换为JSON字节
|
||||||
dataBytes, err := json.Marshal(xingweiResp.Data)
|
dataBytes, err := json.Marshal(xingweiResp.Data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -254,39 +253,39 @@ func (x *XingweiService) CallAPI(ctx context.Context, projectID string, params m
|
|||||||
}
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return dataBytes, nil
|
return dataBytes, nil
|
||||||
|
|
||||||
case CodeNotFound:
|
case CodeNotFound:
|
||||||
// 未查询到结果,返回查空错误
|
// 未查询到结果,返回查空错误
|
||||||
if x.logger != nil {
|
if x.logger != nil {
|
||||||
x.logger.LogError(requestID, transactionID, "xingwei_api",
|
x.logger.LogError(requestID, transactionID, "xingwei_api",
|
||||||
errors.Join(ErrNotFound, fmt.Errorf("未查询到结果")), params)
|
errors.Join(ErrNotFound, fmt.Errorf("未查询到结果")), params)
|
||||||
}
|
}
|
||||||
return nil, errors.Join(ErrNotFound, fmt.Errorf("未查询到结果"))
|
return nil, errors.Join(ErrNotFound, fmt.Errorf("未查询到结果"))
|
||||||
|
|
||||||
case CodeSystemError:
|
case CodeSystemError:
|
||||||
// 系统内部错误
|
// 系统内部错误
|
||||||
errorMsg := GetXingweiErrorMessage(xingweiResp.Code)
|
errorMsg := GetXingweiErrorMessage(xingweiResp.Code)
|
||||||
systemErr := fmt.Errorf("行为数据系统错误[%d]: %s", xingweiResp.Code, errorMsg)
|
systemErr := fmt.Errorf("行为数据系统错误[%d]: %s", xingweiResp.Code, errorMsg)
|
||||||
|
|
||||||
if x.logger != nil {
|
if x.logger != nil {
|
||||||
x.logger.LogError(requestID, transactionID, "xingwei_api",
|
x.logger.LogError(requestID, transactionID, "xingwei_api",
|
||||||
errors.Join(ErrSystem, systemErr), params)
|
errors.Join(ErrSystem, systemErr), params)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, errors.Join(ErrSystem, systemErr)
|
return nil, errors.Join(ErrSystem, systemErr)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
// 其他业务错误
|
// 其他业务错误
|
||||||
errorMsg := GetXingweiErrorMessage(xingweiResp.Code)
|
errorMsg := GetXingweiErrorMessage(xingweiResp.Code)
|
||||||
businessErr := fmt.Errorf("行为数据业务错误[%d]: %s", xingweiResp.Code, errorMsg)
|
businessErr := fmt.Errorf("行为数据业务错误[%d]: %s", xingweiResp.Code, errorMsg)
|
||||||
|
|
||||||
if x.logger != nil {
|
if x.logger != nil {
|
||||||
x.logger.LogError(requestID, transactionID, "xingwei_api",
|
x.logger.LogError(requestID, transactionID, "xingwei_api",
|
||||||
errors.Join(ErrDatasource, businessErr), params)
|
errors.Join(ErrDatasource, businessErr), params)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, errors.Join(ErrDatasource, businessErr)
|
return nil, errors.Join(ErrDatasource, businessErr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,9 +45,12 @@ type ExternalServiceLogger struct {
|
|||||||
// NewExternalServiceLogger 创建外部服务日志器
|
// NewExternalServiceLogger 创建外部服务日志器
|
||||||
func NewExternalServiceLogger(config ExternalServiceLoggingConfig) (*ExternalServiceLogger, error) {
|
func NewExternalServiceLogger(config ExternalServiceLoggingConfig) (*ExternalServiceLogger, error) {
|
||||||
if !config.Enabled {
|
if !config.Enabled {
|
||||||
|
nopLogger := zap.NewNop()
|
||||||
return &ExternalServiceLogger{
|
return &ExternalServiceLogger{
|
||||||
logger: zap.NewNop(),
|
logger: nopLogger,
|
||||||
serviceName: config.ServiceName,
|
serviceName: config.ServiceName,
|
||||||
|
requestLogger: nopLogger,
|
||||||
|
responseLogger: nopLogger,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -186,7 +189,7 @@ func createSeparatedCore(logDir string, config ExternalServiceLoggingConfig) zap
|
|||||||
infoWriter := createFileWriter(logDir, "info", config.LevelConfigs["info"], config.ServiceName, config.UseDaily)
|
infoWriter := createFileWriter(logDir, "info", config.LevelConfigs["info"], config.ServiceName, config.UseDaily)
|
||||||
errorWriter := createFileWriter(logDir, "error", config.LevelConfigs["error"], config.ServiceName, config.UseDaily)
|
errorWriter := createFileWriter(logDir, "error", config.LevelConfigs["error"], config.ServiceName, config.UseDaily)
|
||||||
warnWriter := createFileWriter(logDir, "warn", config.LevelConfigs["warn"], config.ServiceName, config.UseDaily)
|
warnWriter := createFileWriter(logDir, "warn", config.LevelConfigs["warn"], config.ServiceName, config.UseDaily)
|
||||||
|
|
||||||
// 新增:请求和响应日志的独立文件输出
|
// 新增:请求和响应日志的独立文件输出
|
||||||
requestWriter := createFileWriter(logDir, "request", config.RequestLogConfig, config.ServiceName, config.UseDaily)
|
requestWriter := createFileWriter(logDir, "request", config.RequestLogConfig, config.ServiceName, config.UseDaily)
|
||||||
responseWriter := createFileWriter(logDir, "response", config.ResponseLogConfig, config.ServiceName, config.UseDaily)
|
responseWriter := createFileWriter(logDir, "response", config.ResponseLogConfig, config.ServiceName, config.UseDaily)
|
||||||
@@ -293,7 +296,11 @@ func createFileWriter(logDir, level string, config ExternalServiceLevelFileConfi
|
|||||||
|
|
||||||
// LogRequest 记录请求日志
|
// LogRequest 记录请求日志
|
||||||
func (e *ExternalServiceLogger) LogRequest(requestID, transactionID, apiCode string, url interface{}, params interface{}) {
|
func (e *ExternalServiceLogger) LogRequest(requestID, transactionID, apiCode string, url interface{}, params interface{}) {
|
||||||
e.requestLogger.Info(fmt.Sprintf("%s API请求", e.serviceName),
|
logger := e.requestLogger
|
||||||
|
if logger == nil {
|
||||||
|
logger = e.logger
|
||||||
|
}
|
||||||
|
logger.Info(fmt.Sprintf("%s API请求", e.serviceName),
|
||||||
zap.String("service", e.serviceName),
|
zap.String("service", e.serviceName),
|
||||||
zap.String("request_id", requestID),
|
zap.String("request_id", requestID),
|
||||||
zap.String("transaction_id", transactionID),
|
zap.String("transaction_id", transactionID),
|
||||||
@@ -306,7 +313,11 @@ func (e *ExternalServiceLogger) LogRequest(requestID, transactionID, apiCode str
|
|||||||
|
|
||||||
// LogResponse 记录响应日志
|
// LogResponse 记录响应日志
|
||||||
func (e *ExternalServiceLogger) LogResponse(requestID, transactionID, apiCode string, statusCode int, response []byte, duration time.Duration) {
|
func (e *ExternalServiceLogger) LogResponse(requestID, transactionID, apiCode string, statusCode int, response []byte, duration time.Duration) {
|
||||||
e.responseLogger.Info(fmt.Sprintf("%s API响应", e.serviceName),
|
logger := e.responseLogger
|
||||||
|
if logger == nil {
|
||||||
|
logger = e.logger
|
||||||
|
}
|
||||||
|
logger.Info(fmt.Sprintf("%s API响应", e.serviceName),
|
||||||
zap.String("service", e.serviceName),
|
zap.String("service", e.serviceName),
|
||||||
zap.String("request_id", requestID),
|
zap.String("request_id", requestID),
|
||||||
zap.String("transaction_id", transactionID),
|
zap.String("transaction_id", transactionID),
|
||||||
@@ -320,7 +331,11 @@ func (e *ExternalServiceLogger) LogResponse(requestID, transactionID, apiCode st
|
|||||||
|
|
||||||
// LogResponseWithID 记录包含响应ID的响应日志
|
// LogResponseWithID 记录包含响应ID的响应日志
|
||||||
func (e *ExternalServiceLogger) LogResponseWithID(requestID, transactionID, apiCode string, statusCode int, response []byte, duration time.Duration, responseID string) {
|
func (e *ExternalServiceLogger) LogResponseWithID(requestID, transactionID, apiCode string, statusCode int, response []byte, duration time.Duration, responseID string) {
|
||||||
e.responseLogger.Info(fmt.Sprintf("%s API响应", e.serviceName),
|
logger := e.responseLogger
|
||||||
|
if logger == nil {
|
||||||
|
logger = e.logger
|
||||||
|
}
|
||||||
|
logger.Info(fmt.Sprintf("%s API响应", e.serviceName),
|
||||||
zap.String("service", e.serviceName),
|
zap.String("service", e.serviceName),
|
||||||
zap.String("request_id", requestID),
|
zap.String("request_id", requestID),
|
||||||
zap.String("transaction_id", transactionID),
|
zap.String("transaction_id", transactionID),
|
||||||
|
|||||||
Reference in New Issue
Block a user