package hotime import ( "bytes" "encoding/json" "io" "mime/multipart" "net/http" "strings" "sync" "time" . "code.hoteas.com/golang/hotime/common" . "code.hoteas.com/golang/hotime/db" ) type Context struct { *Application Resp http.ResponseWriter Req *http.Request Log Map //日志有则创建 RouterString []string Config Map Db *HoTimeDB RespData Map RespFunc func() //CacheIns SessionIns DataSize int HandlerStr string //复写请求url // 请求参数缓存 reqJsonCache Map // JSON Body 缓存 reqMu sync.Once // 确保 JSON 只解析一次 } // Mtd 唯一标志 func (that *Context) Mtd(router [3]string) Map { that.Application.Router[router[0]][router[1]][router[2]](that) d := that.RespData that.RespData = nil return d } // 打印 func (that *Context) Display(statu int, data interface{}) { resp := Map{"status": statu} if statu != 0 { temp := Map{} tpe := that.Config.GetMap("error").GetString(ObjToStr(statu)) if tpe == "" { //logFmt(errors.New("找不到对应的错误码"), 2, LOG_WARN) } temp["type"] = tpe temp["msg"] = data resp["result"] = temp //兼容android等需要json转对象的服务 resp["error"] = temp } else { resp["result"] = data } that.RespData = resp //that.Data=d; } func (that *Context) View() { if that.RespFunc != nil { that.RespFunc() } if that.RespData == nil { return } //创建日志 if that.Log != nil { that.Log["time"] = time.Now().Format("2006-01-02 15:04") if that.Session("admin_id").Data != nil { that.Log["admin_id"] = that.Session("admin_id").ToCeilInt() } if that.Session("user_id").Data != nil { that.Log["user_id"] = that.Session("user_id").ToCeilInt() } //负载均衡优化 ipStr := "" if that.Req.Header.Get("X-Forwarded-For") != "" { ipStr = that.Req.Header.Get("X-Forwarded-For") } else if that.Req.Header.Get("X-Real-IP") != "" { ipStr = that.Req.Header.Get("X-Real-IP") } //负载均衡优化 if ipStr == "" { //RemoteAddr := that.Req.RemoteAddr ipStr = Substr(that.Req.RemoteAddr, 0, strings.Index(that.Req.RemoteAddr, ":")) } that.Log["ip"] = ipStr that.Db.Insert("logs", that.Log) } d, err := json.Marshal(that.RespData) if err != nil { that.Display(1, err.Error()) that.View() return } that.DataSize = len(d) that.RespData = nil that.Resp.Write(d) } // ==================== 请求参数获取方法 ==================== // ReqParam 获取 URL 查询参数,返回 *Obj 支持链式调用 // 用法: that.ReqParam("id").ToInt() func (that *Context) ReqParam(key string) *Obj { v := that.Req.URL.Query().Get(key) if v == "" { return &Obj{Data: nil} } return &Obj{Data: v} } // ReqForm 获取表单参数,返回 *Obj 支持链式调用 // 用法: that.ReqForm("name").ToStr() func (that *Context) ReqForm(key string) *Obj { v := that.Req.FormValue(key) if v == "" { return &Obj{Data: nil} } return &Obj{Data: v} } // ReqJson 获取 JSON Body 中的字段,返回 *Obj 支持链式调用 // 用法: that.ReqJson("data").ToMap() func (that *Context) ReqJson(key string) *Obj { that.parseJsonBody() if that.reqJsonCache == nil { return &Obj{Data: nil} } return &Obj{Data: that.reqJsonCache.Get(key)} } // parseJsonBody 解析 JSON Body(只解析一次,并发安全) func (that *Context) parseJsonBody() { that.reqMu.Do(func() { if that.Req.Body == nil { return } body, err := io.ReadAll(that.Req.Body) if err != nil || len(body) == 0 { return } // 恢复 Body 以便后续代码可以再次读取 that.Req.Body = io.NopCloser(bytes.NewBuffer(body)) that.reqJsonCache = ObjToMap(string(body)) }) } // ReqData 统一获取请求参数,优先级: JSON > Form > URL // 用法: that.ReqData("id").ToInt() func (that *Context) ReqData(key string) *Obj { // 1. 优先从 JSON Body 获取 that.parseJsonBody() if that.reqJsonCache != nil { if v := that.reqJsonCache.Get(key); v != nil { return &Obj{Data: v} } } // 2. 其次从 Form 获取 if v := that.Req.FormValue(key); v != "" { return &Obj{Data: v} } // 3. 最后从 URL 参数获取 if v := that.Req.URL.Query().Get(key); v != "" { return &Obj{Data: v} } return &Obj{Data: nil} } // ReqFile 获取单个上传文件 // 用法: file, header, err := that.ReqFile("avatar") func (that *Context) ReqFile(name string) (multipart.File, *multipart.FileHeader, error) { return that.Req.FormFile(name) } // ReqFiles 获取多个同名上传文件(批量上传场景) // 用法: files, err := that.ReqFiles("images") func (that *Context) ReqFiles(name string) ([]*multipart.FileHeader, error) { if that.Req.MultipartForm == nil { if err := that.Req.ParseMultipartForm(32 << 20); err != nil { return nil, err } } if that.Req.MultipartForm == nil || that.Req.MultipartForm.File == nil { return nil, http.ErrMissingFile } files, ok := that.Req.MultipartForm.File[name] if !ok { return nil, http.ErrMissingFile } return files, nil }