路由定义
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()获取的会报panic:interface conversion: interface is nil, not http.ResponseWriter,还有其它的方式么
golang获取http.ResponseWriter
- 写回答
- 好问题 0 提建议
- 关注问题
- 邀请回答
-
5条回答 默认 最新
关注让【宝码香车】来帮您解答,本回答参考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,因为:
- 符合 Go 标准库的 HTTP 处理模式
- 代码更清晰,易于理解和维护
- 避免了不必要的 context 操作
- 性能更好
修改后的代码结构更符合 Go 语言的惯用法,能够避免你遇到的 panic 问题。
本回答被题主选为最佳回答 , 对您是否有帮助呢?解决 无用评论 打赏 举报