f
This commit is contained in:
31
config.yaml
31
config.yaml
@@ -713,3 +713,34 @@ nuoer:
|
|||||||
max_backups: 5
|
max_backups: 5
|
||||||
max_age: 30
|
max_age: 30
|
||||||
compress: true
|
compress: true
|
||||||
|
|
||||||
|
# ===========================================
|
||||||
|
# 🌐 海宇API(上游数据源)配置
|
||||||
|
# ===========================================
|
||||||
|
haiyuapi:
|
||||||
|
base_url: "https://api.haiyudata.com"
|
||||||
|
access_id: "2c136588d34b47fd" # 请求头 Access-Id
|
||||||
|
secret_key: "39c5c2c02ff13bf2be0ac0b705e21e28" # Access Key(16进制 AES-128 密钥)
|
||||||
|
timeout: 60s
|
||||||
|
logging:
|
||||||
|
enabled: true
|
||||||
|
log_dir: "logs/external_services"
|
||||||
|
service_name: "haiyuapi"
|
||||||
|
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
|
||||||
@@ -46,6 +46,7 @@ type Config struct {
|
|||||||
PDFGen PDFGenConfig `mapstructure:"pdfgen"`
|
PDFGen PDFGenConfig `mapstructure:"pdfgen"`
|
||||||
Huibo HuiboConfig `mapstructure:"huibo"`
|
Huibo HuiboConfig `mapstructure:"huibo"`
|
||||||
Nuoer NuoerConfig `mapstructure:"nuoer"`
|
Nuoer NuoerConfig `mapstructure:"nuoer"`
|
||||||
|
Haiyuapi HaiyuapiConfig `mapstructure:"haiyuapi"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ServerConfig HTTP服务器配置
|
// ServerConfig HTTP服务器配置
|
||||||
@@ -734,6 +735,34 @@ type NuoerLevelFileConfig struct {
|
|||||||
Compress bool `mapstructure:"compress"`
|
Compress bool `mapstructure:"compress"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HaiyuapiConfig 海宇API(上游数据源)配置
|
||||||
|
type HaiyuapiConfig struct {
|
||||||
|
BaseURL string `mapstructure:"base_url"`
|
||||||
|
AccessID string `mapstructure:"access_id"`
|
||||||
|
SecretKey string `mapstructure:"secret_key"`
|
||||||
|
Timeout time.Duration `mapstructure:"timeout"`
|
||||||
|
|
||||||
|
Logging HaiyuapiLoggingConfig `mapstructure:"logging"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// HaiyuapiLoggingConfig 海宇API日志配置
|
||||||
|
type HaiyuapiLoggingConfig struct {
|
||||||
|
Enabled bool `mapstructure:"enabled"`
|
||||||
|
LogDir string `mapstructure:"log_dir"`
|
||||||
|
ServiceName string `mapstructure:"service_name"`
|
||||||
|
UseDaily bool `mapstructure:"use_daily"`
|
||||||
|
EnableLevelSeparation bool `mapstructure:"enable_level_separation"`
|
||||||
|
LevelConfigs map[string]HaiyuapiLevelFileConfig `mapstructure:"level_configs"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// HaiyuapiLevelFileConfig 海宇API级别文件配置
|
||||||
|
type HaiyuapiLevelFileConfig 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域名
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ import (
|
|||||||
"tyapi-server/internal/infrastructure/external/shumai"
|
"tyapi-server/internal/infrastructure/external/shumai"
|
||||||
"tyapi-server/internal/infrastructure/external/sms"
|
"tyapi-server/internal/infrastructure/external/sms"
|
||||||
"tyapi-server/internal/infrastructure/external/storage"
|
"tyapi-server/internal/infrastructure/external/storage"
|
||||||
|
"tyapi-server/internal/infrastructure/external/haiyuapi"
|
||||||
"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"
|
||||||
@@ -410,6 +411,10 @@ func NewContainer() *Container {
|
|||||||
func(cfg *config.Config) (*nuoer.NuoerService, error) {
|
func(cfg *config.Config) (*nuoer.NuoerService, error) {
|
||||||
return nuoer.NewNuoerServiceWithConfig(cfg)
|
return nuoer.NewNuoerServiceWithConfig(cfg)
|
||||||
},
|
},
|
||||||
|
// HaiyuapiService - 海宇API上游服务
|
||||||
|
func(cfg *config.Config) (*haiyuapi.HaiyuapiService, error) {
|
||||||
|
return haiyuapi.NewHaiyuapiServiceWithConfig(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,
|
||||||
|
|||||||
@@ -608,7 +608,7 @@ type QYGL5A3CReq struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type QYGLBH7YReq struct {
|
type QYGLBH7YReq struct {
|
||||||
EntName string `json:"ent_name" validate:"omitempty,min=1,validEnterpriseName"`
|
EntName string `json:"ent_name" validate:"required,min=1,validEnterpriseName"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type QYGL2naoReq struct {
|
type QYGL2naoReq struct {
|
||||||
|
|||||||
@@ -21,6 +21,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/haiyuapi"
|
||||||
"tyapi-server/internal/infrastructure/external/huibo"
|
"tyapi-server/internal/infrastructure/external/huibo"
|
||||||
"tyapi-server/internal/infrastructure/external/jiguang"
|
"tyapi-server/internal/infrastructure/external/jiguang"
|
||||||
"tyapi-server/internal/infrastructure/external/muzi"
|
"tyapi-server/internal/infrastructure/external/muzi"
|
||||||
@@ -70,6 +71,7 @@ func NewApiRequestService(
|
|||||||
shumaiService *shumai.ShumaiService,
|
shumaiService *shumai.ShumaiService,
|
||||||
huiboService *huibo.HuiboService,
|
huiboService *huibo.HuiboService,
|
||||||
nuoerService *nuoer.NuoerService,
|
nuoerService *nuoer.NuoerService,
|
||||||
|
haiyuapiService *haiyuapi.HaiyuapiService,
|
||||||
validator interfaces.RequestValidator,
|
validator interfaces.RequestValidator,
|
||||||
productManagementService *services.ProductManagementService,
|
productManagementService *services.ProductManagementService,
|
||||||
cfg *appconfig.Config,
|
cfg *appconfig.Config,
|
||||||
@@ -87,6 +89,7 @@ func NewApiRequestService(
|
|||||||
shumaiService,
|
shumaiService,
|
||||||
huiboService,
|
huiboService,
|
||||||
nuoerService,
|
nuoerService,
|
||||||
|
haiyuapiService,
|
||||||
validator,
|
validator,
|
||||||
productManagementService,
|
productManagementService,
|
||||||
cfg,
|
cfg,
|
||||||
@@ -109,6 +112,7 @@ func NewApiRequestServiceWithRepos(
|
|||||||
shumaiService *shumai.ShumaiService,
|
shumaiService *shumai.ShumaiService,
|
||||||
huiboService *huibo.HuiboService,
|
huiboService *huibo.HuiboService,
|
||||||
nuoerService *nuoer.NuoerService,
|
nuoerService *nuoer.NuoerService,
|
||||||
|
haiyuapiService *haiyuapi.HaiyuapiService,
|
||||||
validator interfaces.RequestValidator,
|
validator interfaces.RequestValidator,
|
||||||
productManagementService *services.ProductManagementService,
|
productManagementService *services.ProductManagementService,
|
||||||
cfg *appconfig.Config,
|
cfg *appconfig.Config,
|
||||||
@@ -137,6 +141,7 @@ func NewApiRequestServiceWithRepos(
|
|||||||
shumaiService,
|
shumaiService,
|
||||||
huiboService,
|
huiboService,
|
||||||
nuoerService,
|
nuoerService,
|
||||||
|
haiyuapiService,
|
||||||
validator,
|
validator,
|
||||||
combService,
|
combService,
|
||||||
reportRepo,
|
reportRepo,
|
||||||
@@ -191,7 +196,8 @@ func registerAllProcessors(combService *comb.CombService) {
|
|||||||
"FLXG3A9B": flxg.ProcessFLXG3A9BRequest,
|
"FLXG3A9B": flxg.ProcessFLXG3A9BRequest,
|
||||||
"FLXGK5D2": flxg.ProcessFLXGK5D2Request,
|
"FLXGK5D2": flxg.ProcessFLXGK5D2Request,
|
||||||
"FLXGDJG3": flxg.ProcessFLXGDJG3Request, //董监高司法综合信息核验
|
"FLXGDJG3": flxg.ProcessFLXGDJG3Request, //董监高司法综合信息核验
|
||||||
"FLXGHB4F": flxg.ProcessFLXGHB4FRequest, //个人涉诉案件查询汇博
|
"FLXGHB4F": flxg.ProcessFLXGHB4FRequest, //个人涉诉案件查询(海宇API)
|
||||||
|
|
||||||
// JRZQ系列处理器
|
// JRZQ系列处理器
|
||||||
"JRZQ8203": jrzq.ProcessJRZQ8203Request,
|
"JRZQ8203": jrzq.ProcessJRZQ8203Request,
|
||||||
"JRZQ0A03": jrzq.ProcessJRZQ0A03Request,
|
"JRZQ0A03": jrzq.ProcessJRZQ0A03Request,
|
||||||
@@ -260,11 +266,12 @@ func registerAllProcessors(combService *comb.CombService) {
|
|||||||
"QYGLDJ12": qygl.ProcessQYGLDJ12Request, //企业年报信息核验
|
"QYGLDJ12": qygl.ProcessQYGLDJ12Request, //企业年报信息核验
|
||||||
"QYGL8848": qygl.ProcessQYGL8848Request, //企业税收违法核查
|
"QYGL8848": qygl.ProcessQYGL8848Request, //企业税收违法核查
|
||||||
"QYGLDJ33": qygl.ProcessQYGLDJ33Request, //企业年报信息核验
|
"QYGLDJ33": qygl.ProcessQYGLDJ33Request, //企业年报信息核验
|
||||||
"QYGLBH7Y": qygl.ProcessQYGLBH7YRequest, //企业涉诉案件查询汇博
|
|
||||||
"QYGL4YAB": qygl.ProcessQYGL4YABRequest, //企业四要素认证shumai
|
"QYGL4YAB": qygl.ProcessQYGL4YABRequest, //企业四要素认证shumai
|
||||||
"QYGL3YSB": qygl.ProcessQYGL3YSBRequest, //企业三要素认证shumai
|
"QYGL3YSB": qygl.ProcessQYGL3YSBRequest, //企业三要素认证shumai
|
||||||
"QYGL2YSB": qygl.ProcessQYGL2YSBRequest, //企业二要素认证shumai
|
"QYGL2YSB": qygl.ProcessQYGL2YSBRequest, //企业二要素认证shumai
|
||||||
"QYGLDG77": qygl.ProcessQYGLDG77Request, //企业对公打款认证shumai
|
"QYGLDG77": qygl.ProcessQYGLDG77Request, //企业对公打款认证shumai
|
||||||
|
"QYGLBH7Y": qygl.ProcessQYGLBH7YRequest, //企业涉诉案件查询海宇
|
||||||
|
|
||||||
// YYSY系列处理器
|
// YYSY系列处理器
|
||||||
"YYSY35TA": yysy.ProcessYYSY35TARequest, //运营商归属地数卖
|
"YYSY35TA": yysy.ProcessYYSY35TARequest, //运营商归属地数卖
|
||||||
"YYSYD50F": yysy.ProcessYYSYD50FRequest,
|
"YYSYD50F": yysy.ProcessYYSYD50FRequest,
|
||||||
|
|||||||
@@ -281,8 +281,8 @@ func (s *FormConfigServiceImpl) getDTOStruct(ctx context.Context, apiCode string
|
|||||||
"IVYZRAX1": &dto.IVYZRAX1Req{}, //融安信用分
|
"IVYZRAX1": &dto.IVYZRAX1Req{}, //融安信用分
|
||||||
"IVYZRAX2": &dto.IVYZRAX1Req{}, //融御反欺诈
|
"IVYZRAX2": &dto.IVYZRAX1Req{}, //融御反欺诈
|
||||||
"IVYZ2MN7": &dto.IVYZ2MN6Req{}, //学历Bzhicha
|
"IVYZ2MN7": &dto.IVYZ2MN6Req{}, //学历Bzhicha
|
||||||
"FLXGHB4F": &dto.FLXGHB4FReq{}, //个人涉诉案件查询汇博
|
"FLXGHB4F": &dto.FLXGHB4FReq{}, //个人涉诉案件查询(海宇API)
|
||||||
"QYGLBH7Y": &dto.QYGLBH7YReq{}, //企业涉诉案件查询汇博
|
"QYGLBH7Y": &dto.QYGLBH7YReq{}, //企业涉诉案件查询(海宇API)
|
||||||
"QYGL4YAB": &dto.QYGL4YABReq{}, //企业四要素认证shumai
|
"QYGL4YAB": &dto.QYGL4YABReq{}, //企业四要素认证shumai
|
||||||
"QYGL3YSB": &dto.QYGL3YSBReq{}, //企业三要素认证shumai
|
"QYGL3YSB": &dto.QYGL3YSBReq{}, //企业三要素认证shumai
|
||||||
"QYGL2YSB": &dto.QYGL2YSBReq{}, //企业二要素认证shumai
|
"QYGL2YSB": &dto.QYGL2YSBReq{}, //企业二要素认证shumai
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import (
|
|||||||
"tyapi-server/internal/infrastructure/external/nuoer"
|
"tyapi-server/internal/infrastructure/external/nuoer"
|
||||||
"tyapi-server/internal/infrastructure/external/shujubao"
|
"tyapi-server/internal/infrastructure/external/shujubao"
|
||||||
"tyapi-server/internal/infrastructure/external/shumai"
|
"tyapi-server/internal/infrastructure/external/shumai"
|
||||||
|
"tyapi-server/internal/infrastructure/external/haiyuapi"
|
||||||
"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"
|
||||||
@@ -44,6 +45,7 @@ type ProcessorDependencies struct {
|
|||||||
ShumaiService *shumai.ShumaiService
|
ShumaiService *shumai.ShumaiService
|
||||||
HuiboService *huibo.HuiboService
|
HuiboService *huibo.HuiboService
|
||||||
NuoerService *nuoer.NuoerService
|
NuoerService *nuoer.NuoerService
|
||||||
|
HaiyuapiService *haiyuapi.HaiyuapiService
|
||||||
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支持
|
||||||
@@ -73,6 +75,7 @@ func NewProcessorDependencies(
|
|||||||
shumaiService *shumai.ShumaiService,
|
shumaiService *shumai.ShumaiService,
|
||||||
huiboService *huibo.HuiboService,
|
huiboService *huibo.HuiboService,
|
||||||
nuoerService *nuoer.NuoerService,
|
nuoerService *nuoer.NuoerService,
|
||||||
|
haiyuapiService *haiyuapi.HaiyuapiService,
|
||||||
validator interfaces.RequestValidator,
|
validator interfaces.RequestValidator,
|
||||||
combService CombServiceInterface, // Changed to interface
|
combService CombServiceInterface, // Changed to interface
|
||||||
reportRepo repositories.ReportRepository,
|
reportRepo repositories.ReportRepository,
|
||||||
@@ -92,6 +95,7 @@ func NewProcessorDependencies(
|
|||||||
ShumaiService: shumaiService,
|
ShumaiService: shumaiService,
|
||||||
HuiboService: huiboService,
|
HuiboService: huiboService,
|
||||||
NuoerService: nuoerService,
|
NuoerService: nuoerService,
|
||||||
|
HaiyuapiService: haiyuapiService,
|
||||||
Validator: validator,
|
Validator: validator,
|
||||||
CombService: combService,
|
CombService: combService,
|
||||||
Options: nil, // 初始化为nil,在调用时设置
|
Options: nil, // 初始化为nil,在调用时设置
|
||||||
|
|||||||
@@ -7,54 +7,40 @@ import (
|
|||||||
|
|
||||||
"tyapi-server/internal/domains/api/dto"
|
"tyapi-server/internal/domains/api/dto"
|
||||||
"tyapi-server/internal/domains/api/services/processors"
|
"tyapi-server/internal/domains/api/services/processors"
|
||||||
"tyapi-server/internal/infrastructure/external/huibo"
|
"tyapi-server/internal/infrastructure/external/haiyuapi"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ProcessFLXGHB4FRequest FLXGHB4F API处理方法 - 个人涉诉案件查询汇博
|
// ProcessFLXGHB4FRequest FLXGHB4F API处理方法 - 个人涉诉案件查询(海宇API)
|
||||||
func ProcessFLXGHB4FRequest(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
|
func ProcessFLXGHB4FRequest(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
|
||||||
var paramsDto dto.FLXGHB4FReq
|
var paramsDto dto.FLXGHB4FReq
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
if deps.HuiboService == nil {
|
if err := deps.Validator.ValidateStruct(paramsDto); err != nil {
|
||||||
return nil, errors.Join(processors.ErrSystem, errors.New("汇博服务未初始化"))
|
return nil, errors.Join(processors.ErrInvalidParam, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 使用 MD5 加密 name 和 idCard
|
if deps.HaiyuapiService == nil {
|
||||||
// encryptedName := "MD5:" + huibo.MD5Encrypt(paramsDto.Name, deps.HuiboService.GetConfig().AppKey)
|
return nil, errors.Join(processors.ErrSystem, errors.New("海宇API服务未初始化"))
|
||||||
// encryptedIDCard := "MD5:" + huibo.MD5Encrypt(paramsDto.IDCard, deps.HuiboService.GetConfig().AppKey)
|
}
|
||||||
|
|
||||||
reqdata := map[string]interface{}{
|
reqParams := map[string]interface{}{
|
||||||
"name": paramsDto.Name,
|
"name": paramsDto.Name,
|
||||||
"idCard": paramsDto.IDCard,
|
"id_card": paramsDto.IDCard,
|
||||||
}
|
}
|
||||||
|
|
||||||
respBytes, err := deps.HuiboService.CallAPI2(ctx, "P_004_0271", reqdata)
|
apiPath := "/api/v1/FLXGHB4F"
|
||||||
|
respBytes, err := deps.HaiyuapiService.CallAPI(ctx, apiPath, reqParams)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if errors.Is(err, haiyuapi.ErrNotFound) {
|
||||||
|
return nil, errors.Join(processors.ErrNotFound, err)
|
||||||
|
}
|
||||||
|
if errors.Is(err, haiyuapi.ErrDatasource) {
|
||||||
return nil, errors.Join(processors.ErrDatasource, err)
|
return nil, errors.Join(processors.ErrDatasource, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 解析响应
|
|
||||||
var response huibo.CallAPI2Response
|
|
||||||
if err := json.Unmarshal(respBytes, &response); err != nil {
|
|
||||||
return nil, errors.Join(processors.ErrSystem, err)
|
return nil, errors.Join(processors.ErrSystem, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 处理状态码
|
|
||||||
switch response.Code {
|
|
||||||
case huibo.CallAPI2StatusSuccess:
|
|
||||||
// 查询成功
|
|
||||||
if response.Data == nil {
|
|
||||||
return []byte("{}"), nil
|
|
||||||
}
|
|
||||||
return respBytes, nil
|
return respBytes, nil
|
||||||
case huibo.CallAPI2StatusNoData:
|
|
||||||
// 查询成功,无数据 - 按产品约定按调用成功计费
|
|
||||||
return []byte("{}"), nil
|
|
||||||
default:
|
|
||||||
// 其他错误状态码
|
|
||||||
message := huibo.GetCallAPI2StatusMessage(response.Code)
|
|
||||||
return nil, errors.Join(processors.ErrDatasource, errors.New(message))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import (
|
|||||||
|
|
||||||
"tyapi-server/internal/domains/api/dto"
|
"tyapi-server/internal/domains/api/dto"
|
||||||
"tyapi-server/internal/domains/api/services/processors"
|
"tyapi-server/internal/domains/api/services/processors"
|
||||||
"tyapi-server/internal/infrastructure/external/huibo"
|
"tyapi-server/internal/infrastructure/external/haiyuapi"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ProcessQYGLBH7YRequest QYGLBH7Y API处理方法 - 企业案件查询汇博
|
// ProcessQYGLBH7YRequest QYGLBH7Y API处理方法 - 企业案件查询汇博
|
||||||
@@ -17,39 +17,25 @@ func ProcessQYGLBH7YRequest(ctx context.Context, params []byte, deps *processors
|
|||||||
return nil, errors.Join(processors.ErrSystem, err)
|
return nil, errors.Join(processors.ErrSystem, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if deps.HuiboService == nil {
|
if deps.HaiyuapiService == nil {
|
||||||
return nil, errors.Join(processors.ErrSystem, errors.New("汇博服务未初始化"))
|
return nil, errors.Join(processors.ErrSystem, errors.New("海宇API服务未初始化"))
|
||||||
}
|
}
|
||||||
|
|
||||||
reqdata := map[string]interface{}{
|
reqParams := map[string]interface{}{
|
||||||
"companyName": paramsDto.EntName,
|
"ent_name": paramsDto.EntName,
|
||||||
}
|
}
|
||||||
|
|
||||||
respBytes, err := deps.HuiboService.CallAPI2(ctx, "E_004_0261", reqdata)
|
apiPath := "/api/v1/QYGLBH7Y"
|
||||||
|
respBytes, err := deps.HaiyuapiService.CallAPI(ctx, apiPath, reqParams)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if errors.Is(err, haiyuapi.ErrNotFound) {
|
||||||
|
return nil, errors.Join(processors.ErrNotFound, err)
|
||||||
|
}
|
||||||
|
if errors.Is(err, haiyuapi.ErrDatasource) {
|
||||||
return nil, errors.Join(processors.ErrDatasource, err)
|
return nil, errors.Join(processors.ErrDatasource, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 解析响应
|
|
||||||
var response huibo.CallAPI2Response
|
|
||||||
if err := json.Unmarshal(respBytes, &response); err != nil {
|
|
||||||
return nil, errors.Join(processors.ErrSystem, err)
|
return nil, errors.Join(processors.ErrSystem, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 处理状态码
|
|
||||||
switch response.Code {
|
|
||||||
case huibo.CallAPI2StatusSuccess:
|
|
||||||
// 查询成功
|
|
||||||
if response.Data == nil {
|
|
||||||
return []byte("{}"), nil
|
|
||||||
}
|
|
||||||
return respBytes, nil
|
return respBytes, nil
|
||||||
case huibo.CallAPI2StatusNoData:
|
|
||||||
// 查询成功,无数据 - 按产品约定按调用成功计费
|
|
||||||
return []byte("{}"), nil
|
|
||||||
default:
|
|
||||||
// 其他错误状态码
|
|
||||||
message := huibo.GetCallAPI2StatusMessage(response.Code)
|
|
||||||
return nil, errors.Join(processors.ErrDatasource, errors.New(message))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
24
internal/infrastructure/external/haiyuapi/crypto.go
vendored
Normal file
24
internal/infrastructure/external/haiyuapi/crypto.go
vendored
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
package haiyuapi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"tyapi-server/internal/shared/crypto"
|
||||||
|
)
|
||||||
|
|
||||||
|
// EncryptParams 将业务参数序列化为 JSON 后,使用 Access Key(16进制)AES-128-CBC 加密并 Base64 编码
|
||||||
|
func EncryptParams(params map[string]interface{}, accessKey string) (string, error) {
|
||||||
|
plainJSON, err := json.Marshal(params)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return crypto.AesEncrypt(plainJSON, accessKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecryptData 解密响应 data 字段(IV+密文 Base64);空字符串视为无数据,返回 {}
|
||||||
|
func DecryptData(encrypted, accessKey string) ([]byte, error) {
|
||||||
|
if encrypted == "" {
|
||||||
|
return []byte("{}"), nil
|
||||||
|
}
|
||||||
|
return crypto.AesDecrypt(encrypted, accessKey)
|
||||||
|
}
|
||||||
93
internal/infrastructure/external/haiyuapi/haiyuapi_errors.go
vendored
Normal file
93
internal/infrastructure/external/haiyuapi/haiyuapi_errors.go
vendored
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
package haiyuapi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 海宇API平台返回码
|
||||||
|
const (
|
||||||
|
CodeSuccess = 0 // 业务成功
|
||||||
|
CodeQueryEmpty = 1000 // 查询为空
|
||||||
|
CodeSystem = 1001 // 接口异常
|
||||||
|
CodeDecryptFail = 1002 // 参数解密失败
|
||||||
|
CodeRequestParam = 1003 // 基础参数校验不正确
|
||||||
|
CodeInvalidIP = 1004 // 未经授权的IP
|
||||||
|
CodeMissingAccessID = 1005 // 缺少Access-Id
|
||||||
|
CodeInvalidAccessID = 1006 // 未经授权的AccessId
|
||||||
|
CodeInsufficientBalance = 1007 // 账户余额不足,无法请求
|
||||||
|
CodeProductNotSubscribed = 1008 // 未开通此产品
|
||||||
|
CodeBusiness = 2001 // 业务失败
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrDatasource = errors.New("数据源异常")
|
||||||
|
ErrSystem = errors.New("系统异常")
|
||||||
|
ErrNotFound = errors.New("查询为空")
|
||||||
|
)
|
||||||
|
|
||||||
|
// haiyuapiAPIError 海宇API平台错误
|
||||||
|
type haiyuapiAPIError struct {
|
||||||
|
Code int
|
||||||
|
Message string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *haiyuapiAPIError) Error() string {
|
||||||
|
return fmt.Sprintf("海宇API返回错误,code: %d,message: %s", e.Code, e.Message)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewHaiyuapiAPIError 创建平台错误
|
||||||
|
func NewHaiyuapiAPIError(code int, message string) *haiyuapiAPIError {
|
||||||
|
if message == "" {
|
||||||
|
if desc := GetPlatformCodeDesc(code); desc != "" {
|
||||||
|
message = desc
|
||||||
|
} else {
|
||||||
|
message = "海宇API返回未知错误"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &haiyuapiAPIError{Code: code, Message: message}
|
||||||
|
}
|
||||||
|
|
||||||
|
// platformCodeDesc 平台 code -> 官方 message
|
||||||
|
var platformCodeDesc = map[int]string{
|
||||||
|
CodeSuccess: "业务成功",
|
||||||
|
CodeQueryEmpty: "查询为空",
|
||||||
|
CodeSystem: "接口异常",
|
||||||
|
CodeDecryptFail: "参数解密失败",
|
||||||
|
CodeRequestParam: "基础参数校验不正确",
|
||||||
|
CodeInvalidIP: "未经授权的IP",
|
||||||
|
CodeMissingAccessID: "缺少Access-Id",
|
||||||
|
CodeInvalidAccessID: "未经授权的AccessId",
|
||||||
|
CodeInsufficientBalance: "账户余额不足,无法请求",
|
||||||
|
CodeProductNotSubscribed: "未开通此产品",
|
||||||
|
CodeBusiness: "业务失败",
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPlatformCodeDesc 根据平台 code 获取描述
|
||||||
|
func GetPlatformCodeDesc(code int) string {
|
||||||
|
if desc, ok := platformCodeDesc[code]; ok {
|
||||||
|
return desc
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetErrByCode 将海宇API code 映射为内部哨兵错误,供处理器 errors.Is 判断
|
||||||
|
//
|
||||||
|
// 1000 -> ErrNotFound(查询为空,可按产品约定当成功处理)
|
||||||
|
// 1001, 1002, 1003 -> ErrSystem(接口/解密/参数校验异常)
|
||||||
|
// 1004~1008, 2001 -> ErrDatasource(鉴权、余额、产品、业务类上游错误)
|
||||||
|
func GetErrByCode(code int) error {
|
||||||
|
switch code {
|
||||||
|
case CodeSuccess:
|
||||||
|
return nil
|
||||||
|
case CodeQueryEmpty:
|
||||||
|
return ErrNotFound
|
||||||
|
case CodeSystem, CodeDecryptFail, CodeRequestParam:
|
||||||
|
return ErrSystem
|
||||||
|
case CodeInvalidIP, CodeMissingAccessID, CodeInvalidAccessID,
|
||||||
|
CodeInsufficientBalance, CodeProductNotSubscribed, CodeBusiness:
|
||||||
|
return ErrDatasource
|
||||||
|
default:
|
||||||
|
return ErrDatasource
|
||||||
|
}
|
||||||
|
}
|
||||||
64
internal/infrastructure/external/haiyuapi/haiyuapi_factory.go
vendored
Normal file
64
internal/infrastructure/external/haiyuapi/haiyuapi_factory.go
vendored
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
package haiyuapi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"tyapi-server/internal/config"
|
||||||
|
"tyapi-server/internal/shared/external_logger"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewHaiyuapiServiceWithConfig 使用配置创建海宇API服务
|
||||||
|
func NewHaiyuapiServiceWithConfig(cfg *config.Config) (*HaiyuapiService, error) {
|
||||||
|
loggingConfig := external_logger.ExternalServiceLoggingConfig{
|
||||||
|
Enabled: cfg.Haiyuapi.Logging.Enabled,
|
||||||
|
LogDir: cfg.Haiyuapi.Logging.LogDir,
|
||||||
|
ServiceName: "haiyuapi",
|
||||||
|
UseDaily: cfg.Haiyuapi.Logging.UseDaily,
|
||||||
|
EnableLevelSeparation: cfg.Haiyuapi.Logging.EnableLevelSeparation,
|
||||||
|
LevelConfigs: make(map[string]external_logger.ExternalServiceLevelFileConfig),
|
||||||
|
}
|
||||||
|
|
||||||
|
for level, levelCfg := range cfg.Haiyuapi.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
|
||||||
|
}
|
||||||
|
|
||||||
|
timeout := cfg.Haiyuapi.Timeout
|
||||||
|
if timeout <= 0 {
|
||||||
|
timeout = defaultRequestTimeout
|
||||||
|
}
|
||||||
|
|
||||||
|
return NewHaiyuapiService(
|
||||||
|
cfg.Haiyuapi.BaseURL,
|
||||||
|
cfg.Haiyuapi.AccessID,
|
||||||
|
cfg.Haiyuapi.SecretKey,
|
||||||
|
timeout,
|
||||||
|
logger,
|
||||||
|
), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewHaiyuapiServiceWithLogging 使用自定义日志配置创建海宇API服务
|
||||||
|
func NewHaiyuapiServiceWithLogging(baseURL, accessID, secretKey string, timeout time.Duration, loggingConfig external_logger.ExternalServiceLoggingConfig) (*HaiyuapiService, error) {
|
||||||
|
loggingConfig.ServiceName = "haiyuapi"
|
||||||
|
|
||||||
|
logger, err := external_logger.NewExternalServiceLogger(loggingConfig)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return NewHaiyuapiService(baseURL, accessID, secretKey, timeout, logger), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewHaiyuapiServiceSimple 创建无日志的海宇API服务
|
||||||
|
func NewHaiyuapiServiceSimple(baseURL, accessID, secretKey string, timeout time.Duration) *HaiyuapiService {
|
||||||
|
return NewHaiyuapiService(baseURL, accessID, secretKey, timeout, nil)
|
||||||
|
}
|
||||||
178
internal/infrastructure/external/haiyuapi/haiyuapi_service.go
vendored
Normal file
178
internal/infrastructure/external/haiyuapi/haiyuapi_service.go
vendored
Normal file
@@ -0,0 +1,178 @@
|
|||||||
|
package haiyuapi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"crypto/md5"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"tyapi-server/internal/shared/external_logger"
|
||||||
|
)
|
||||||
|
|
||||||
|
const defaultRequestTimeout = 60 * time.Second
|
||||||
|
|
||||||
|
// serviceConfig 海宇API服务运行时配置(Access Key 为 16 进制 AES-128 密钥)
|
||||||
|
type serviceConfig struct {
|
||||||
|
BaseURL string
|
||||||
|
AccessID string
|
||||||
|
SecretKey string
|
||||||
|
Timeout time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
// HaiyuapiService 海宇API上游服务客户端
|
||||||
|
type HaiyuapiService struct {
|
||||||
|
config serviceConfig
|
||||||
|
logger *external_logger.ExternalServiceLogger
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewHaiyuapiService 创建海宇API服务实例
|
||||||
|
func NewHaiyuapiService(baseURL, accessID, secretKey string, timeout time.Duration, logger *external_logger.ExternalServiceLogger) *HaiyuapiService {
|
||||||
|
if timeout <= 0 {
|
||||||
|
timeout = defaultRequestTimeout
|
||||||
|
}
|
||||||
|
return &HaiyuapiService{
|
||||||
|
config: serviceConfig{
|
||||||
|
BaseURL: strings.TrimRight(baseURL, "/"),
|
||||||
|
AccessID: accessID,
|
||||||
|
SecretKey: secretKey,
|
||||||
|
Timeout: timeout,
|
||||||
|
},
|
||||||
|
logger: logger,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CallAPI 调用海宇API:apiPath 如 /api/v1/FLXGHB4F,自动拼接 base_url 与 ?t=13位毫秒时间戳,返回解密后的明文 JSON
|
||||||
|
func (s *HaiyuapiService) CallAPI(ctx context.Context, apiPath string, params map[string]interface{}) ([]byte, error) {
|
||||||
|
startTime := time.Now()
|
||||||
|
hash := md5.Sum([]byte(fmt.Sprintf("%d_%s", time.Now().UnixNano(), s.config.SecretKey)))
|
||||||
|
requestID := fmt.Sprintf("haiyuapi_%x", hash[:8])
|
||||||
|
|
||||||
|
var transactionID string
|
||||||
|
if id, ok := ctx.Value("transaction_id").(string); ok {
|
||||||
|
transactionID = id
|
||||||
|
}
|
||||||
|
|
||||||
|
path := apiPath
|
||||||
|
if !strings.HasPrefix(path, "/") {
|
||||||
|
path = "/" + path
|
||||||
|
}
|
||||||
|
timestamp := strconv.FormatInt(time.Now().UnixMilli(), 10)
|
||||||
|
reqURL := s.config.BaseURL + path + "?t=" + timestamp
|
||||||
|
|
||||||
|
if s.logger != nil {
|
||||||
|
s.logger.LogRequest(requestID, transactionID, apiPath, reqURL)
|
||||||
|
}
|
||||||
|
|
||||||
|
encryptedData, err := EncryptParams(params, s.config.SecretKey)
|
||||||
|
if err != nil {
|
||||||
|
err = errors.Join(ErrSystem, fmt.Errorf("请求加密失败: %w", err))
|
||||||
|
if s.logger != nil {
|
||||||
|
s.logger.LogError(requestID, transactionID, apiPath, err, params)
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
bodyBytes, err := json.Marshal(RequestPayload{Data: encryptedData})
|
||||||
|
if err != nil {
|
||||||
|
err = errors.Join(ErrSystem, err)
|
||||||
|
if s.logger != nil {
|
||||||
|
s.logger.LogError(requestID, transactionID, apiPath, err, params)
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := http.NewRequestWithContext(ctx, http.MethodPost, reqURL, bytes.NewBuffer(bodyBytes))
|
||||||
|
if err != nil {
|
||||||
|
err = errors.Join(ErrSystem, err)
|
||||||
|
if s.logger != nil {
|
||||||
|
s.logger.LogError(requestID, transactionID, apiPath, err, params)
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
req.Header.Set(HeaderContentType, ContentTypeJSON)
|
||||||
|
req.Header.Set(HeaderAccessID, s.config.AccessID)
|
||||||
|
|
||||||
|
resp, err := (&http.Client{Timeout: s.config.Timeout}).Do(req)
|
||||||
|
if err != nil {
|
||||||
|
err = wrapHTTPError(err)
|
||||||
|
if s.logger != nil {
|
||||||
|
s.logger.LogError(requestID, transactionID, apiPath, err, params)
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
respBody, err := io.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
err = errors.Join(ErrSystem, err)
|
||||||
|
if s.logger != nil {
|
||||||
|
s.logger.LogError(requestID, transactionID, apiPath, err, params)
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
duration := time.Since(startTime)
|
||||||
|
|
||||||
|
if resp.StatusCode != http.StatusOK {
|
||||||
|
err = errors.Join(ErrDatasource, fmt.Errorf("HTTP状态码 %d", resp.StatusCode))
|
||||||
|
if s.logger != nil {
|
||||||
|
s.logger.LogError(requestID, transactionID, apiPath, err, params)
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var apiResp APIResponse
|
||||||
|
if err := json.Unmarshal(respBody, &apiResp); err != nil {
|
||||||
|
err = errors.Join(ErrSystem, fmt.Errorf("响应解析失败: %w", err))
|
||||||
|
if s.logger != nil {
|
||||||
|
s.logger.LogError(requestID, transactionID, apiPath, err, params)
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if apiResp.Code != CodeSuccess {
|
||||||
|
apiErr := NewHaiyuapiAPIError(apiResp.Code, apiResp.Message)
|
||||||
|
err = errors.Join(GetErrByCode(apiResp.Code), apiErr)
|
||||||
|
if s.logger != nil {
|
||||||
|
s.logger.LogError(requestID, transactionID, apiPath, apiErr, params)
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
plainResp, err := DecryptData(apiResp.Data, s.config.SecretKey)
|
||||||
|
if err != nil {
|
||||||
|
err = errors.Join(ErrSystem, fmt.Errorf("响应解密失败: %w", err))
|
||||||
|
if s.logger != nil {
|
||||||
|
s.logger.LogError(requestID, transactionID, apiPath, err, params)
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.logger != nil {
|
||||||
|
s.logger.LogResponse(requestID, transactionID, apiPath, resp.StatusCode, duration)
|
||||||
|
}
|
||||||
|
|
||||||
|
return plainResp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func wrapHTTPError(err error) error {
|
||||||
|
if err == context.DeadlineExceeded {
|
||||||
|
return errors.Join(ErrDatasource, err)
|
||||||
|
}
|
||||||
|
if netErr, ok := err.(interface{ Timeout() bool }); ok && netErr.Timeout() {
|
||||||
|
return errors.Join(ErrDatasource, err)
|
||||||
|
}
|
||||||
|
switch err.Error() {
|
||||||
|
case "context deadline exceeded", "timeout", "Client.Timeout exceeded", "net/http: request canceled":
|
||||||
|
return errors.Join(ErrDatasource, err)
|
||||||
|
default:
|
||||||
|
return errors.Join(ErrSystem, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
21
internal/infrastructure/external/haiyuapi/haiyuapi_types.go
vendored
Normal file
21
internal/infrastructure/external/haiyuapi/haiyuapi_types.go
vendored
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
package haiyuapi
|
||||||
|
|
||||||
|
// HTTP 请求头
|
||||||
|
const (
|
||||||
|
HeaderAccessID = "Access-Id"
|
||||||
|
HeaderContentType = "Content-Type"
|
||||||
|
ContentTypeJSON = "application/json"
|
||||||
|
)
|
||||||
|
|
||||||
|
// APIResponse 海宇API公共响应(data 为 AES 加密后的 Base64 字符串)
|
||||||
|
type APIResponse struct {
|
||||||
|
Code int `json:"code"`
|
||||||
|
Message string `json:"message"`
|
||||||
|
TransactionID string `json:"transaction_id"`
|
||||||
|
Data string `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// RequestPayload 海宇API请求体(业务参数加密后置于 data)
|
||||||
|
type RequestPayload struct {
|
||||||
|
Data string `json:"data"`
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user