showliuzp 2025-10-11 11:52 采纳率: 84.3%
浏览 4
已结题

golang获取http.ResponseWriter


路由定义
func add_router(method_type string, path string, handler http.HandlerFunc) rest.Route {
    return rest.Route{
        Method:  method_type,
        Path:    types.Admin_Http_URL_Prefix + path,
        Handler: handler,
    }
}

//execl导出
add_router(types.GET,"/finance/business/salary/export",response.WrapResponse(BusinessSalaryExport,nil)),   //财务管理-业务员待发工资导出

controller:

//财务管理-业务员待发工资-导出
func BusinessSalaryExport(r *http.Request) (resp interface{},err error){
    var req = new(iapi.BusinessSalaryListReq)
    if resp,err = ParseReq(r,&req,"财务管理-业务员待发工资-导出,前端参数错误",log_tag_user_streamer);err != nil{
        return
    }

    w := r.Context().Value("responseWriter").(http.ResponseWriter)
    finance_obj.BusinessSalaryExport(w,req,(*r).Header.Get(types.HEADER_AUTH))

    return nil,nil
}

//BusinessSalaryExport
func (f *Finance) BusinessSalaryExport(w http.ResponseWriter,req *iapi.BusinessSalaryListReq,authorization string){
    funs_log_tag := "财务管理-业务员待发工资导出"
 
    var err error
    //fmt.Printf("header头:%+v\n",*r)
    if err = f.get_token_detail(&authorization);err != nil{
        fmt.Printf("错误:%+v\n",err)
        return
    }
 
    (*req).PageSize = 1000
    list,_,err := dao.BusinessSalaryList(f.TokenDetail.GuildId,req)
    if err != nil{
        logx.Error(fmt.Sprintf("tags:%+v,%+v,数据库异常,req:%+v,err:%+v", f.LogTag,req,funs_log_tag,err))
        return
    }
    fmt.Printf("list:%+v\n",list)
 
 
    fs := excelize.NewFile()
    defer fs.Close()
 
    // 创建工作表并设置表头
    index, err := fs.NewSheet("业务员工资")
    if err != nil {
        fmt.Println(err)
        http.Error(w, "创建Excel失败", http.StatusInternalServerError)
        return
    }
    
    fs.SetActiveSheet(index)
 
 
    // 设置表头
    headers := []string{"姓名", "工号", "部门", "基本工资", "绩效工资", "应发工资", "状态"}
    for i, header := range headers {
        cell, _ := excelize.CoordinatesToCellName(i+1, 1)
        fs.SetCellValue("业务员工资", cell, header)
    }
 
 
    // 填充数据(根据您的数据结构调整)
    for i, _ := range list {
        row := i + 2 // 从第2行开始,第1行是表头
        // 示例数据填充,根据您的实际数据结构调整
        fs.SetCellValue("业务员工资", fmt.Sprintf("A%d", row), "aaa")
        fs.SetCellValue("业务员工资", fmt.Sprintf("B%d", row), "bbb")
        // ... 继续设置其他单元格
    }
 
    // 设置响应头,触发文件下载
    w.Header().Set("Content-Type", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
    w.Header().Set("Content-Disposition", "attachment; filename=business_salary.xlsx")
    w.Header().Set("Content-Transfer-Encoding", "binary")
    w.Header().Set("Cache-Control", "no-cache")
 
 
    // 将Excel文件写入HTTP响应
    if err := fs.Write(w); err != nil {
        fmt.Printf("写入Excel到响应失败: %+v\n", err)
        http.Error(w, "导出失败", http.StatusInternalServerError)
        return
    }
    return
}

我需要获取http.ResponseWriter,并作为参数传给BusinessSalaryExport,从而导出execl文件,但目前的通过context()获取的会报panicinterface conversion: interface is nil, not http.ResponseWriter,还有其它的方式么
  • 写回答

5条回答 默认 最新

  • 宝码香车 优质创作者: JavaScript技术领域 2025-10-11 11:54
    关注

    让【宝码香车】来帮您解答,本回答参考DeepSeek编写,并整理提供。

    如果答案让您满意,请采纳、点赞、关注,非常感谢!
    .
    每日一句正能量,让它带给您好心情:困难像一面墙,翻过去,就能看到不一样的风景。
    .

    根据你的代码分析,问题出现在通过 r.Context().Value("responseWriter") 获取 http.ResponseWriter 时返回了 nil。这是因为在标准的 HTTP 处理流程中,http.ResponseWriter 通常不会存储在 context 中。

    解决方案

    方案1:修改路由处理方式(推荐)

    将你的路由定义改为直接传递 http.ResponseWriter

    // 修改路由定义
    add_router(types.GET, "/finance/business/salary/export", BusinessSalaryExportHandler)
    
    
    // 创建专门的HTTP处理函数
    func BusinessSalaryExportHandler(w http.ResponseWriter, r *http.Request) {
        var req = new(iapi.BusinessSalaryListReq)
        if _, err := ParseReq(r, &req, "财务管理-业务员待发工资-导出,前端参数错误", log_tag_user_streamer); err != nil {
            http.Error(w, err.Error(), http.StatusBadRequest)
            return
        }
    
    
        authorization := r.Header.Get(types.HEADER_AUTH)
        finance_obj.BusinessSalaryExport(w, req, authorization)
    }
    
    
    // 修改controller函数签名
    func BusinessSalaryExport(r *http.Request) (resp interface{}, err error) {
        // 这个函数现在不需要了,或者可以删除
        return nil, nil
    }
    

    方案2:使用中间件存储 ResponseWriter

    如果必须使用当前的架构,可以通过中间件将 ResponseWriter 存入 context:

    // 中间件
    func ResponseWriterMiddleware(next http.HandlerFunc) http.HandlerFunc {
        return func(w http.ResponseWriter, r *http.Request) {
            ctx := context.WithValue(r.Context(), "responseWriter", w)
            next.ServeHTTP(w, r.WithContext(ctx))
        }
    }
    
    
    // 路由定义中使用中间件
    add_router(types.GET, "/finance/business/salary/export", 
        ResponseWriterMiddleware(response.WrapResponse(BusinessSalaryExport, nil)))
    

    方案3:重构 BusinessSalaryExport 函数

    BusinessSalaryExport 改为标准的 HTTP 处理函数:

    // 直接作为http.HandlerFunc使用
    func BusinessSalaryExport(w http.ResponseWriter, r *http.Request) {
        var req = new(iapi.BusinessSalaryListReq)
        if _, err := ParseReq(r, &req, "财务管理-业务员待发工资-导出,前端参数错误", log_tag_user_streamer); err != nil {
            http.Error(w, err.Error(), http.StatusBadRequest)
            return
        }
    
    
        authorization := r.Header.Get(types.HEADER_AUTH)
        
        // 调用实际的业务逻辑
        finance_obj.BusinessSalaryExportLogic(w, req, authorization)
    }
    
    
    // 修改Finance结构体的方法
    func (f *Finance) BusinessSalaryExportLogic(w http.ResponseWriter, req *iapi.BusinessSalaryListReq, authorization string) {
        // 原有的BusinessSalaryExport函数内容...
    }
    

    推荐做法

    我推荐使用方案1,因为:

    1. 符合 Go 标准库的 HTTP 处理模式
    2. 代码更清晰,易于理解和维护
    3. 避免了不必要的 context 操作
    4. 性能更好

    修改后的代码结构更符合 Go 语言的惯用法,能够避免你遇到的 panic 问题。

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

报告相同问题?

问题事件

  • 系统已结题 10月19日
  • 已采纳回答 10月11日
  • 创建了问题 10月11日