showliuzp 2025-09-27 17:57 采纳率: 84.3%
浏览 3
已结题

golang中间件弹性封装

services.go
type TokenDetail struct{
    Token       *string
    TokenDetail *iapi.LoginToken
}

controller.go

func AfterTokenAccountValidation(req interface{}, token string) (interface{}, error) {
    // 创建 TokenDetail 实例
    tokenDetail := &services.TokenDetail{
        Token: &token,
    }

    // 定义 wrapped_handler 作为 TokenHandler 类型的函数
    wrappedHandler := func(req interface{}, token *services.TokenDetail) (interface{}, error) {
        reqParams, ok := req.(*iapi.UserStreamerListReq)
        if !ok {
            return nil, fmt.Errorf("转换类型错误")
        }

        resp, err := user_streamer_obj.UserStreamerList(reqParams, *token)
        return resp, err
    }

    // 使用 WithTokenAccountValidation 包装 handler 并执行
    handler := services.WithTokenAccountValidation(wrappedHandler)
    return handler(req, tokenDetail)
}

我想让这个AfterTokenAccountValidation函数更具通用性,比如req.(*iapi.UserStreamerListReq),能换成不同的结构体,user_streamer_obj.UserStreamerList(reqParams, *token)也可以更换,应该怎么做
  • 写回答

4条回答 默认 最新

  • 檀越@新空间 2025-09-27 17:58
    关注

    下午好🌅🌅🌅
    本答案参考通义千问

    为了使 AfterTokenAccountValidation 函数更具通用性,我们需要将 请求结构体的类型转换业务逻辑的调用 从硬编码中解耦出来。可以通过以下方式实现:


    目标

    • 让函数能够处理多种不同的请求结构体(如 *iapi.UserStreamerListReq, *iapi.LoginReq, 等)。
    • 允许在调用时动态指定业务逻辑方法(如 user_streamer_obj.UserStreamerList 或其他服务方法)。

    解决方案

    1. 定义一个通用的处理器函数签名

    使用 func(req interface{}, token *services.TokenDetail) (interface{}, error) 作为通用的 handler 接口。

    2. 封装 Token 验证中间件为通用版本

    WithTokenAccountValidation 改造成可以接受任意 handler 的形式。

    3. 通过闭包或参数传递业务逻辑

    user_streamer_obj.UserStreamerList 替换为一个可配置的函数参数。


    修改后的代码示例

    services.go(保持原样,除非需要扩展)

    package services
    
    type TokenDetail struct {
        Token       *string
        TokenDetail *iapi.LoginToken
    }
    
    // WithTokenAccountValidation 是一个中间件函数,用于包装带有 Token 验证的 handler
    func WithTokenAccountValidation(handler func(req interface{}, token *TokenDetail) (interface{}, error)) func(interface{}, *TokenDetail) (interface{}, error) {
        return func(req interface{}, token *TokenDetail) (interface{}, error) {
            // 这里可以添加 Token 验证逻辑
            if token == nil || token.Token == nil || *token.Token == "" {
                return nil, fmt.Errorf("无效的 Token")
            }
    
            return handler(req, token)
        }
    }
    

    controller.go(修改后的版本)

    package controller
    
    import (
        "fmt"
        "your_project/iapi"
        "your_project/services"
    )
    
    // GenericHandler 是一个通用的 handler 类型,接收 req 和 token,并返回结果和错误
    type GenericHandler func(req interface{}, token *services.TokenDetail) (interface{}, error)
    
    // AfterTokenAccountValidation 是一个通用的验证函数,支持动态传入业务逻辑
    func AfterTokenAccountValidation(req interface{}, token string, handlerFunc GenericHandler) (interface{}, error) {
        tokenDetail := &services.TokenDetail{
            Token: &token,
        }
    
        // 使用中间件包装 handler
        wrappedHandler := services.WithTokenAccountValidation(handlerFunc)
    
        return wrappedHandler(req, tokenDetail)
    }
    

    如何调用这个通用函数?

    示例 1:调用 UserStreamerList

    func HandleUserStreamerList(req interface{}, token *services.TokenDetail) (interface{}, error) {
        reqParams, ok := req.(*iapi.UserStreamerListReq)
        if !ok {
            return nil, fmt.Errorf("类型转换错误")
        }
    
        // 假设 user_streamer_obj 是已初始化的服务对象
        resp, err := user_streamer_obj.UserStreamerList(reqParams, *token)
        return resp, err
    }
    
    // 调用方式
    result, err := AfterTokenAccountValidation(req, token, HandleUserStreamerList)
    

    示例 2:调用 Login 方法(假设是另一个服务)

    func HandleLogin(req interface{}, token *services.TokenDetail) (interface{}, error) {
        reqParams, ok := req.(*iapi.LoginReq)
        if !ok {
            return nil, fmt.Errorf("类型转换错误")
        }
    
        resp, err := auth_service.Login(reqParams, *token)
        return resp, err
    }
    
    // 调用方式
    result, err := AfterTokenAccountValidation(req, token, HandleLogin)
    

    总结

    | 问题 | 解决方案 | |------|----------| | req.(*iapi.UserStreamerListReq) 是硬编码的 | 将其替换为泛型函数,由外部传入 | | user_streamer_obj.UserStreamerList(...) 是固定的 | 将其作为参数传入,支持多服务调用 | | 函数不够通用 | 使用闭包和接口设计,提升复用性 |


    最终建议

    • 抽象出 GenericHandler 类型,统一 handler 接口。
    • 使用闭包或函数参数 来灵活切换业务逻辑。
    • 保持中间件逻辑独立,只做 Token 验证,不涉及具体业务逻辑。

    如果你有多个类似的业务方法,也可以进一步封装成通用的服务调用器。

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(3条)

报告相同问题?

问题事件

  • 系统已结题 10月5日
  • 已采纳回答 9月27日
  • 创建了问题 9月27日