tianyuan-api-server/API调用流程域设计.md

450 lines
14 KiB
Markdown
Raw Normal View History

2025-07-13 20:37:12 +08:00
# API 调用流程域设计分析
## 🎯 业务流程分析
根据你描述的场景,这是一个典型的**B2B 数据服务 API 调用流程**
```
用户企业 → 调用我们的产品API → 获取第三方大数据服务 → 计费扣款
```
## 🏗️ 涉及的业务域分析
这个流程总共涉及 **6 个核心域**
### 1. 🚪 **网关域 (Gateway Domain)**
- **职责**: 统一入口、基础路由、请求预处理
- **功能**:
- 接收所有外部请求
- 基础的请求验证
- 路由到具体的业务域
### 2. 🛡️ **安全域 (Security Domain)**
- **职责**: 认证授权、加密解密、白名单管理
- **功能**:
- IP 白名单验证
- 企业 ID 验证
- 密钥管理
- 请求参数解密
### 3. 👤 **用户域 (User Domain)**
- **职责**: 用户和企业信息管理
- **功能**:
- 企业认证信息验证
- 用户权限检查
- 企业密钥获取
### 4. 📦 **产品域 (Product Domain)**
- **职责**: 产品访问控制、权限管理
- **功能**:
- 产品访问权限验证
- API 限额检查
- 产品配置管理
### 5. 📊 **数据服务域 (Data Service Domain)**
- **职责**: 核心业务逻辑、第三方 API 调用
- **功能**:
- 参数处理和转换
- 调用上游数据公司 API
- 数据格式转换和响应
### 6. 💰 **计费域 (Billing Domain)**
- **职责**: 计费扣款、账单管理
- **功能**:
- 钱包余额检查
- 费用计算
- 扣款操作
- 计费记录
### 7. 📋 **审计域 (Audit Domain)**
- **职责**: 请求记录、日志管理
- **功能**:
- API 调用记录
- 操作日志
- 审计追踪
## 🔄 完整流程设计
### 架构图
```
┌─────────────┐
│ 客户端 │
└─────────────┘
┌─────────────────────────────────────────────────────────────┐
│ 网关域 (Gateway) │
│ • 请求接收 • 基础验证 • 路由分发 • 响应聚合 │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ 数据服务域 (Data Service) │
│ [主要协调者] │
└─────────────────────────────────────────────────────────────┘
│ │ │ │ │ │
▼ ▼ ▼ ▼ ▼ ▼
┌────────┐┌────────┐┌────────┐┌────────┐┌────────┐┌────────┐
│安全域 ││用户域 ││产品域 ││计费域 ││审计域 ││第三方 │
│Security││User ││Product ││Billing ││Audit ││API │
└────────┘└────────┘└────────┘└────────┘└────────┘└────────┘
```
### 详细流程设计
```go
// 完整的API调用流程
func (h *DataServiceHandler) ProcessAPIRequest(ctx context.Context, req *APIRequest) (*APIResponse, error) {
// 1. 审计域 - 开始记录
auditID := h.auditService.StartRequest(ctx, req)
defer h.auditService.EndRequest(ctx, auditID)
// 2. 安全域 - IP白名单验证
if err := h.securityService.ValidateIP(ctx, req.ClientIP); err != nil {
return nil, errors.Wrap(err, "IP not in whitelist")
}
// 3. 用户域 - 企业ID验证
enterprise, err := h.userService.GetEnterpriseByID(ctx, req.EnterpriseID)
if err != nil {
return nil, errors.Wrap(err, "invalid enterprise ID")
}
// 4. 安全域 - 获取密钥并解密参数
secretKey, err := h.securityService.GetEnterpriseSecret(ctx, req.EnterpriseID)
if err != nil {
return nil, errors.Wrap(err, "failed to get enterprise secret")
}
decryptedParams, err := h.securityService.DecryptParams(ctx, req.EncryptedParams, secretKey)
if err != nil {
return nil, errors.Wrap(err, "failed to decrypt parameters")
}
// 5. 产品域 - 产品权限验证
if err := h.productService.ValidateAccess(ctx, enterprise.ID, req.ProductCode); err != nil {
return nil, errors.Wrap(err, "no access to product")
}
// 6. 计费域 - 检查余额
cost, err := h.billingService.CalculateCost(ctx, req.ProductCode, decryptedParams)
if err != nil {
return nil, errors.Wrap(err, "failed to calculate cost")
}
if err := h.billingService.CheckBalance(ctx, enterprise.ID, cost); err != nil {
return nil, errors.Wrap(err, "insufficient balance")
}
// 7. 数据服务域 - 调用第三方API
upstreamResp, err := h.callUpstreamAPI(ctx, decryptedParams)
if err != nil {
return nil, errors.Wrap(err, "upstream API call failed")
}
// 8. 计费域 - 扣费
if err := h.billingService.ChargeAccount(ctx, enterprise.ID, cost, auditID); err != nil {
// 记录扣费失败,但不影响响应
h.logger.Error("charge failed", zap.Error(err), zap.String("audit_id", auditID))
}
// 9. 安全域 - 加密响应
encryptedResp, err := h.securityService.EncryptResponse(ctx, upstreamResp, secretKey)
if err != nil {
return nil, errors.Wrap(err, "failed to encrypt response")
}
return &APIResponse{
Data: encryptedResp,
RequestID: auditID,
}, nil
}
```
## 🚪 路由入口设计
### 1. 网关层路由配置
```yaml
# gateway.yaml
routes:
- path: /api/v1/data/*
service: data-service
middlewares:
- request-id # 生成请求ID
- rate-limit # 基础限流
- audit-start # 开始审计
timeout: 60s
- path: /api/v1/admin/*
service: admin-service
middlewares: [admin-auth, rate-limit]
- path: /api/v1/user/*
service: user-service
middlewares: [user-auth, rate-limit]
```
### 2. 网关中间件
```go
// 网关层的请求预处理中间件
func DataAPIMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
// 1. 生成请求ID
requestID := uuid.New().String()
c.Set("request_id", requestID)
c.Header("X-Request-ID", requestID)
// 2. 提取企业ID从Header或路径参数
enterpriseID := extractEnterpriseID(c)
if enterpriseID == "" {
c.JSON(http.StatusBadRequest, gin.H{"error": "missing enterprise ID"})
c.Abort()
return
}
c.Set("enterprise_id", enterpriseID)
// 3. 提取客户端IP
clientIP := c.ClientIP()
c.Set("client_ip", clientIP)
// 4. 提取产品代码
productCode := c.Param("product_code")
c.Set("product_code", productCode)
c.Next()
}
}
func extractEnterpriseID(c *gin.Context) string {
// 优先从Header获取
if id := c.GetHeader("X-Enterprise-ID"); id != "" {
return id
}
// 从路径参数获取
return c.Param("enterprise_id")
}
```
### 3. 数据服务域作为主协调者
```go
// 数据服务域的HTTP处理器
type DataServiceHandler struct {
securityService *SecurityService
userService *UserService
productService *ProductService
billingService *BillingService
auditService *AuditService
upstreamClient *UpstreamAPIClient
logger *zap.Logger
}
// API端点定义
func (h *DataServiceHandler) RegisterRoutes(r *gin.RouterGroup) {
// 具体的数据产品API
r.POST("/financial-data", h.GetFinancialData)
r.POST("/credit-check", h.GetCreditCheck)
r.POST("/risk-assessment", h.GetRiskAssessment)
r.POST("/company-info", h.GetCompanyInfo)
}
// 具体业务处理器
func (h *DataServiceHandler) GetFinancialData(c *gin.Context) {
ctx := c.Request.Context()
// 构建请求对象
req := &APIRequest{
RequestID: c.GetString("request_id"),
EnterpriseID: c.GetString("enterprise_id"),
ProductCode: "FINANCIAL_DATA",
ClientIP: c.GetString("client_ip"),
EncryptedParams: c.PostForm("data"),
}
// 调用业务逻辑
resp, err := h.ProcessAPIRequest(ctx, req)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{
"error": err.Error(),
"request_id": req.RequestID,
})
return
}
c.JSON(http.StatusOK, resp)
}
```
## 🔄 域间通信设计
### 1. 事件驱动架构
```go
// 定义领域事件
type APIRequestStarted struct {
RequestID string `json:"request_id"`
EnterpriseID string `json:"enterprise_id"`
ProductCode string `json:"product_code"`
ClientIP string `json:"client_ip"`
Timestamp time.Time `json:"timestamp"`
}
type APIRequestCompleted struct {
RequestID string `json:"request_id"`
EnterpriseID string `json:"enterprise_id"`
ProductCode string `json:"product_code"`
Success bool `json:"success"`
Cost float64 `json:"cost"`
Duration int64 `json:"duration_ms"`
Timestamp time.Time `json:"timestamp"`
}
type ChargeRequired struct {
RequestID string `json:"request_id"`
EnterpriseID string `json:"enterprise_id"`
Amount float64 `json:"amount"`
ProductCode string `json:"product_code"`
}
```
### 2. 异步处理
```go
// 异步计费处理
func (s *BillingService) HandleChargeRequired(event ChargeRequired) error {
// 异步处理计费,避免阻塞主流程
go func() {
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
if err := s.ProcessCharge(ctx, event); err != nil {
s.logger.Error("async charge failed",
zap.Error(err),
zap.String("request_id", event.RequestID))
// 发送补偿事件
s.eventBus.Publish(ChargeFailed{
RequestID: event.RequestID,
Error: err.Error(),
})
}
}()
return nil
}
```
## 📊 性能和可扩展性考虑
### 1. 缓存策略
```go
// 多级缓存策略
type CacheStrategy struct {
// L1: 本地缓存 (企业信息、产品配置)
localCache *cache.Cache
// L2: Redis缓存 (密钥、白名单)
redisCache *redis.Client
// L3: 数据库
db *gorm.DB
}
func (cs *CacheStrategy) GetEnterpriseSecret(enterpriseID string) (string, error) {
// L1缓存查找
if secret, found := cs.localCache.Get("secret:" + enterpriseID); found {
return secret.(string), nil
}
// L2缓存查找
if secret, err := cs.redisCache.Get(context.Background(), "secret:"+enterpriseID).Result(); err == nil {
cs.localCache.Set("secret:"+enterpriseID, secret, 5*time.Minute)
return secret, nil
}
// L3数据库查找
var enterprise Enterprise
if err := cs.db.Where("id = ?", enterpriseID).First(&enterprise).Error; err != nil {
return "", err
}
// 写入缓存
cs.redisCache.Set(context.Background(), "secret:"+enterpriseID, enterprise.SecretKey, time.Hour)
cs.localCache.Set("secret:"+enterpriseID, enterprise.SecretKey, 5*time.Minute)
return enterprise.SecretKey, nil
}
```
### 2. 熔断器模式
```go
// 上游API调用熔断器
func (s *DataService) callUpstreamAPI(ctx context.Context, params map[string]interface{}) (*UpstreamResponse, error) {
return s.circuitBreaker.Execute(func() (interface{}, error) {
client := &http.Client{Timeout: 30 * time.Second}
// 构建请求
reqBody, _ := json.Marshal(params)
req, _ := http.NewRequestWithContext(ctx, "POST", s.upstreamURL, bytes.NewBuffer(reqBody))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", "Bearer "+s.upstreamToken)
// 发送请求
resp, err := client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
// 解析响应
var upstreamResp UpstreamResponse
if err := json.NewDecoder(resp.Body).Decode(&upstreamResp); err != nil {
return nil, err
}
return &upstreamResp, nil
})
}
```
## 🎯 总结
### 涉及的域数量:**7 个域**
1. 网关域 - 统一入口
2. 安全域 - 认证加密
3. 用户域 - 企业验证
4. 产品域 - 权限控制
5. 数据服务域 - 核心业务
6. 计费域 - 扣费计算
7. 审计域 - 请求记录
### 路由入口设计:
- **主入口**: 网关域 (`/api/v1/data/`)
- **业务协调**: 数据服务域作为主要协调者
- **域间通信**: 通过 gRPC 调用和事件总线
### 设计优势:
1. **清晰的职责分离** - 每个域专注自己的业务
2. **高可扩展性** - 可以独立扩展任何一个域
3. **易于测试** - 每个域可以独立测试
4. **容错性强** - 单个域故障不影响整体
5. **性能优化** - 多级缓存和异步处理
这种设计既保证了业务逻辑的清晰性,又确保了系统的高性能和高可用性。