第二天:封装Context
原创Golang框架源码上下文大约 1 分钟
第二天:封装Context
痛点分析
我们现在的处理函数入参是 http.ResponseWriter, *http.Request 每个接口的处理需要设置太多的参数,粒度太细 比如,响应头(状态码,响应格式),响应状态码,响应体
支持restfull请求,就需要解析路径上的参数,需要存储
我们就需要根据以上的需求,封装为context
封装
先定义这个结构体
type Context struct {
Writer http.ResponseWriter
Req *http.Request
StatusCode int
Path string
}
尝试做一个类似gin的参数获取
// 表单
func (ctx *Context) PostForm(k string) string {
return ctx.Req.FormValue(k)
}
func (ctx *Context) Query(k string) string {
return ctx.Req.URL.Query().Get(k)
}
响应头
func (ctx *Context) Status(code int) {
ctx.StatusCode = code
ctx.Writer.WriteHeader(code)
}
func (ctx *Context) SetHeader(k, v string) {
ctx.Writer.Header().Set(k, v)
}
响应体
func (ctx *Context) JSON(code int, body interface{}) {
ctx.SetHeader("Content-Type", "application/json")
ctx.Status(code)
if bytes, err := json.Marshal(body); err != nil {
http.Error(ctx.Writer, err.Error(), 500)
} else {
_, err = ctx.Writer.Write(bytes)
if err != nil {
http.Error(ctx.Writer, err.Error(), 500)
}
}
}
func (ctx *Context) String(code int, format string, v ...interface{}) {
ctx.SetHeader("Content-Type", "text/plain")
ctx.Status(code)
if _, err := ctx.Writer.Write([]byte(fmt.Sprintf(format, v...))); err != nil {
http.Error(ctx.Writer, err.Error(), 500)
}
}
为了使用更简洁,定义一个别名
type H map[string]interface{}
调整入参
我们还差将处理函数入参改为Context
// type HandleFunc func(http.ResponseWriter, *http.Request)
type HandleFunc func(*Context)
// 只有 ServeHTTP 方法报错,改了就行
func (e *Engine) ServeHTTP(w http.ResponseWriter, r *http.Request) {
k := r.Method + "_" + r.URL.Path
ctx := &Context{
Req: r,
Writer: w,
}
if handleFunc, ok := e.router[k]; ok {
handleFunc(ctx)
} else {
ctx.String(http.StatusNotFound, "404 NOT FOUND: %s\n", ctx.Path)
}
}
测试
func main() {
e := lee.New()
e.Get("/sayHello", handleFunc)
e.Run("localhost:8080")
}
func handleFunc(ctx *lee.Context) {
ctx.JSON(200, lee.H{
"code": 200,
"msg": "成功",
"data": lee.H{
"name": "lll",
"age": 18,
},
})
}
