目录

一 Gin对象的构建

Gin框架是基于golang官方的http包搭建起来的,http包最重要的实现是:

func ListenAndServe(addr string, handler Handler) error {
    server := &Server{Addr: addr, Handler: handler}
    return server.ListenAndServe()
}

利用该方法,以及参数中的Handler接口,实现Gin的Engine,Context:

package engine

import "net/http"

type Engine struct {

}

func (e *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) {

}

context对象其实就是对ServeHTTP方法参数的封装,因为这2个参数在web开发中一个完整请求链中都会用到:

type Context struct {
    writermem   responseWriter
    Request     *http.Request
    Writer      ResponseWriter
}

type responseWriter struct {
    http.ResponseWriter
    size        int
    status      int
}

这里多了一个属性 writermem,如果仅仅只从功能上考虑,这里有了Request、Writer已经足够使用了,但是框架需要应对多变的返回数据情况,必须对其进行封装,比如:

type ResponseWriter interface {

    http.ResponseWriter

    Pusher() http.Pusher

    Status() int
    Size() int
    WriteString(string) (int, error)
    Written() bool
    WriteHeaderNow()
}

这里对外暴露的是接口RespnserWriter,内部的http.ResponseWriter实现原生的ResponseWriter接口,在reset()的时候进行拷贝即可:

func (c *Context) reset() {
    c.Writer = &c.writermem
    c.Params = c.Params[0:0]
    c.handlers = nil
    c.index = -1
    c.Keys = nil
    c.Errors = c.Errors[0:0]
    c.Accepted = nil
}

这样做能够更好的符合面向接口编程的概念。

Context也可以通过对象池复用提升性能:

type Engine struct {
    pool             sync.Pool
}

func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) {
    c := engine.pool.Get().(*Context)
    c.writermem.reset(w)
    c.Request = req
    c.reset()

    engine.handleHTTPRequest(c)

    engine.pool.Put(c)
}

紧接着就可以在Context的基础上实现其大量的常用方法了:

func (c *Context) Param(key string) string{
    return ""
}

func (c *Context) Query(key string) string {
    return ""
}

func (c *Context) DefaultQuery(key, defaultValue string) string {
    return ""
}


func (c *Context) PostFormArray(key string) []string{
    return nil
}