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}