showliuzp 2025-09-27 14:25 采纳率: 84.3%
浏览 2
已结题

golang中间件重复代码封装


type TokenHandler func(req interface{}, token_detail *TokenDetail) (interface{}, error)

//oken内容中间件处理
func WithTokenAccountValidation(handler TokenHandler) TokenHandler {
    return func(req interface{}, token *TokenDetail) (interface{}, error) {
        token_detail, err := tools.ParseToken((*token).Token)
        if err != nil {
            return nil, err
        }

        (*token).TokenDetail = token_detail
        return handler(req, token)
    }
}

方法一:
//用户管理-主播列表-主播退出
func UserStreamerQuit(r *http.Request) (resp interface{},err error){
    authorization := (*r).Header.Get(types.HEADER_AUTH)

    var req = new(iapi.UserStreamerStatusReq)
    if resp,err = ParseReq(r,&req,"用户管理-列表-退出,前端参数错误",log_tag_user_streamer);err != nil{
        return
    }

    wrapped_handler := func(req interface{}, token *services.TokenDetail) (resp interface{}, err error) {
        req_params, ok := req.(*iapi.UserStreamerStatusReq)
        if !ok {
            return nil, fmt.Errorf("转换类型错误")
        }

        resp, err = user_streamer_obj.UserStreamerQuit(req_params, *token)

        return
    }

    resp,err = services.WithTokenAccountValidation(wrapped_handler)(req,&(services.TokenDetail{Token:&authorization}))

    return
}

方法二:
func UserStreamerStatus(r *http.Request) (resp interface{},err error){
    authorization := (*r).Header.Get(types.HEADER_AUTH)

    var req = new(iapi.UserStreamerStatusReq)
    if resp,err = ParseReq(r,&req,"用户管理-主播列表-主播状态变更,前端参数错误",log_tag_user_streamer);err != nil{
        return
    }

    if req.Status >2 || req.Status < 1{
        return nil, response.NewErrCodeMsg(200, "参数不正确")
    }

    wrapped_handler := func(req interface{}, token *services.TokenDetail) (resp interface{}, err error) {
        req_params, ok := req.(*iapi.UserStreamerStatusReq)
        if !ok {
            return nil, fmt.Errorf("转换类型错误")
        }

        resp, err = user_streamer_obj.UserStreamerStatus(req_params, *token)

        return
    }

    resp,err = services.WithTokenAccountValidation(wrapped_handler)(req,&(services.TokenDetail{Token:&authorization}))

    return
}


方法1和方法二都有重复调用中间的代码,比较臃肿,
臃肿点:
   1、authorization := (*r).Header.Get(types.HEADER_AUTH)
    2、wrapped_handler := func(req interface{}, token *services.TokenDetail) (resp interface{}, err error) {
        req_params, ok := req.(*iapi.UserStreamerStatusReq)
        if !ok {
            return nil, fmt.Errorf("转换类型错误")
        }

        resp, err = user_streamer_obj.UserStreamerStatus(req_params, *token)

        return
    }

    resp,err = services.WithTokenAccountValidation(wrapped_handler)(req,&(services.TokenDetail{Token:&authorization}))

我想对这部分代码进行复用,应该怎么做
  • 写回答

3条回答 默认 最新

  • 檀越@新空间 2025-09-27 14:26
    关注

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

    为了减少方法一和方法二中的重复代码,我们可以将公共逻辑提取为一个通用的封装函数,这样可以避免在每个处理函数中重复编写相同的逻辑。


    目标

    • 封装 获取 token 信息 的逻辑
    • 封装 类型转换调用业务逻辑 的逻辑
    • 减少重复的 wrapped_handler 定义

    解决方案

    1. 提取 Token 解析逻辑

    我们将从请求中获取 token 的部分封装到一个独立函数中。

    // GetTokenFromRequest 获取请求中的 token 字符串
    func GetTokenFromRequest(r *http.Request) (string, error) {
        authHeader := r.Header.Get(types.HEADER_AUTH)
        if authHeader == "" {
            return "", fmt.Errorf("缺少 Authorization 头")
        }
        return authHeader, nil
    }
    

    2. 封装通用的 handler 调用逻辑

    创建一个通用函数来处理以下步骤:

    • 解析 token
    • 构建 TokenDetail 对象
    • 创建 wrapped_handler
    • 调用 WithTokenAccountValidation 中间件
    • 返回结果
    // HandleWithTokenAndParseReq 是一个通用的封装函数
    func HandleWithTokenAndParseReq(
        r *http.Request,
        reqType interface{},
        handlerFunc func(req *iapi.UserStreamerStatusReq, token *services.TokenDetail) (interface{}, error),
        errMsg string,
        logTag string,
    ) (interface{}, error) {
        // 1. 获取 token
        tokenStr, err := GetTokenFromRequest(r)
        if err != nil {
            return nil, err
        }
    
        // 2. 解析请求参数
        var req = reqType
        if resp, err := ParseReq(r, req, errMsg, logTag); err != nil {
            return resp, err
        }
    
        // 3. 构建 TokenDetail
        tokenDetail := &services.TokenDetail{Token: &tokenStr}
    
        // 4. 创建 wrapped_handler
        wrappedHandler := func(req interface{}, token *services.TokenDetail) (interface{}, error) {
            reqParams, ok := req.(*iapi.UserStreamerStatusReq)
            if !ok {
                return nil, fmt.Errorf("类型转换失败")
            }
    
            return handlerFunc(reqParams, token)
        }
    
        // 5. 调用中间件
        result, err := services.WithTokenAccountValidation(wrappedHandler)(req, tokenDetail)
    
        return result, err
    }
    

    3. 修改方法一和方法二以使用通用函数

    方法一(UserStreamerQuit)修改如下:
    func UserStreamerQuit(r *http.Request) (resp interface{}, err error) {
        return HandleWithTokenAndParseReq(
            r,
            new(iapi.UserStreamerStatusReq),
            func(req *iapi.UserStreamerStatusReq, token *services.TokenDetail) (interface{}, error) {
                return user_streamer_obj.UserStreamerQuit(req, *token)
            },
            "用户管理-列表-退出,前端参数错误",
            log_tag_user_streamer,
        )
    }
    
    方法二(UserStreamerStatus)修改如下:
    func UserStreamerStatus(r *http.Request) (resp interface{}, err error) {
        // 额外校验 status
        authorization, _ := GetTokenFromRequest(r)
        req := new(iapi.UserStreamerStatusReq)
        if resp, err := ParseReq(r, req, "用户管理-主播列表-主播状态变更,前端参数错误", log_tag_user_streamer); err != nil {
            return resp, err
        }
    
        if req.Status > 2 || req.Status < 1 {
            return nil, response.NewErrCodeMsg(200, "参数不正确")
        }
    
        return HandleWithTokenAndParseReq(
            r,
            req,
            func(req *iapi.UserStreamerStatusReq, token *services.TokenDetail) (interface{}, error) {
                return user_streamer_obj.UserStreamerStatus(req, *token)
            },
            "用户管理-主播列表-主播状态变更,前端参数错误",
            log_tag_user_streamer,
        )
    }
    

    总结:优化点

    1. 统一 Token 解析逻辑

      • 使用 GetTokenFromRequest 封装 token 获取逻辑
    2. 复用类型转换与 handler 构建逻辑

      • 使用 HandleWithTokenAndParseReq 统一处理请求解析、token 处理、handler 构建
    3. 减少重复代码

      • 每个接口只需定义自己的业务逻辑,无需重复写 wrapped_handler 或 token 解析

    最终效果

    通过上述封装,你可以将原本分散在多个方法中的重复逻辑集中到一个通用函数中,提高代码可维护性和可读性。

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

报告相同问题?

问题事件

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