go server框架学习之路 – 写一个自己的go框架
go server框架学习之路 – 写一个自己的go框架
1 创建一个简单的框架
代码
package https import "net/http" // 创建自己的引擎 type Engine struct { } // 实现engine的ServeHTTP 有了这个方法 engine就属于一个http的handle了 func (e *Engine)ServeHTTP(w http.ResponseWriter, r *http.Request) { w.Write([]byte("HTTP/1.0 200 OKrn" + "rn" + "你好中国")) } func Run() { http.ListenAndServe(":8080",&Engine{}) }
测试代码和执行结果:
package main import "gcw/pkg/https" func main() { https.Run() } **************************************** HTTP/1.0 200 OK 你好中国
2 封装请求和响应
代码
package https import "net/http" // 统一上下文 以后写自己的 视图函数就不用写一长串参数了 type Context struct { Request *http.Request Writer http.ResponseWriter } // 定义自己的HandlerFunc type HandlerFunc func(*Context) // 实现自己的HandlerFunc的ServeHTTP方法 func (f HandlerFunc) ServeHTTP(c *Context) { f(c) } // 创建自己的引擎 type Engine struct {} // 实现engine的ServeHTTP 有了这个方法 engine就属于一个http的handle了 func (e *Engine)ServeHTTP(w http.ResponseWriter, r *http.Request) { c := &Context{ Request: r, Writer: w, } testHandlerFunc(c) } func testHandlerFunc(c *Context) { c.Writer.Write([]byte("测试2")) } func Run() { //http.Handle("/", &Engine{}) http.ListenAndServe(":8080",&Engine{}) }
测试代码和执行结果:
测试代码同1 ************************ 测试2
3 实现路由功能
代码
package https import "net/http" // 统一上下文 以后写自己的 视图函数就不用写一长串参数了 type Context struct { Request *http.Request Writer http.ResponseWriter index int8 // 配合next 执行handlers handlers []HandlerFunc // } // 执行下一个handle func (c *Context) Next() { c.index++ for c.index < int8(len(c.handlers)) { c.handlers[c.index](c) c.index++ } } // 定义自己的HandlerFunc type HandlerFunc func(*Context) // 实现自己的HandlerFunc的ServeHTTP方法 func (f HandlerFunc) ServeHTTP(c *Context) { f(c) } // 路由 type Router struct { method string root string handles []HandlerFunc } // 往engine 的 routers 中添加路由 func (e *Engine)AddRouter(method string, path string , h []HandlerFunc) { e.routers[method+"_"+path] = &Router{ method: method, root: path, handles: h, } } func (e *Engine)Get(path string, h ...HandlerFunc) { e.AddRouter("GET", path, h) } func (e *Engine)POST(path string, h ...HandlerFunc) { e.AddRouter("POST", path, h) } // 创建自己的引擎 type Engine struct { routers map[string]*Router } // 通过new 创建engine 初始化参数 func New() *Engine{ return &Engine{routers:make(map[string]*Router)} } // 实现engine的ServeHTTP 有了这个方法 engine就属于一个http的handle了 func (e *Engine)ServeHTTP(w http.ResponseWriter, r *http.Request) { method := r.Method path := r.RequestURI //remoteAddr := r.RemoteAddr router := e.routers[method+"_"+path] c := &Context{ Request: r, Writer: w, index: -1, handlers: router.handles, } c.Next() } func (e *Engine)Run() { //http.Handle("/", &Engine{}) http.ListenAndServe(":8080",e) }
测试代码和执行结果:
package main import "gcw/pkg/https" func main() { app := https.New() app.Get("/hello", testHandlerFunc) app.Run() } func testHandlerFunc(c *https.Context) { c.Writer.Write([]byte("测试3")) }
4 完善路由404
代码
// 实现engine的ServeHTTP 有了这个方法 engine就属于一个http的handle了 func (e *Engine)ServeHTTP(w http.ResponseWriter, r *http.Request) { method := r.Method path := r.RequestURI //remoteAddr := r.RemoteAddr router := e.routers[method+"_"+path] if router == nil { w.Write([]byte("404 你访问的页面不存在")) return } c := &Context{ Request: r, Writer: w, index: -1, handlers: router.handles, } c.Next() }
测试代码和执行结果:
404 你访问的页面不存在
5 日志打印功能
新建logger.go
package https import ( "fmt" "path" "runtime" "time" ) type loggerMessage struct { Millisecond int64 `json:"timestamp"` MillisecondFormat string `json:"time_format"` LevelString string `json:"level_string"` Body string `json:"body"` Position string `json:"position"` } type Logger struct { } func (logger *Logger) Writer(level string, msg string){ funcName := "null" pc, file, line, ok := runtime.Caller(2) if !ok { file = "null" line = 0 } else { funcName = runtime.FuncForPC(pc).Name() } _, filename := path.Split(file) loggerMsg := &loggerMessage{ Millisecond: time.Now().UnixNano() / 1e6, MillisecondFormat: time.Now().Format("2006-01-02 15:04:05.999"), LevelString: level, Body: msg, Position: fmt.Sprintf("%s %d %s", filename, line, funcName), } logger.OutPut(loggerMsg) } func (logger *Logger)OutPut(msg *loggerMessage) { fmt.Println(msg) } func (logger *Logger)Info(msg string) { logger.Writer("info", msg) }
engine 和 new中添加初始化log
func New() *Engine{ return &Engine{ routers:make(map[string]*Router), log:Logger{}, } } type Engine struct { routers map[string]*Router log Logger }
使用 及效果
tts = time.Now().UnixNano() - tts e.log.Info(fmt.Sprintf("%s %s %s %3.6fs",remoteAddr, method, path, float64(float64(tts)/1e9))) func (e *Engine)Run() { //http.Handle("/", &Engine{}) e.log.Info("服务器启动: 127.0.0.1:8080") http.ListenAndServe(":8080",e) } *************************************** &{1586071294752 2020-04-05 15:21:34.752 info 服务器启动: 127.0.0.1:8080 server.go 79 gcw/pkg/https.(*Engine).Run} &{1586071298492 2020-04-05 15:21:38.492 info 127.0.0.1:54446 GET /hello 0.000000s server.go 66 gcw/pkg/https.(*Engine).ServeHTTP}