go簡化web框架實現

框架結構參考另一篇文章golang基於context的web範式git

簡單http server實現github

簡單http 框架實現golang

直接上框架簡化實現的代碼:web

package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"strings"
	"time"
)

type (
	// App 框架主體
	App struct {
		Addr string
		Logger
		Router
		Server
		Middlewares []MiddlewareFunc
	}
	// HandleFunc 請求處理函數
	HandleFunc func(*Context) // MiddlewareFunc 中間件函數 MiddlewareFunc func(HandleFunc) HandleFunc // Logger 日誌輸出接口 Logger interface {
		Print(...interface{})
		Printf(string, ...interface{})
	}
	// Router 路由器接口
	Router interface {
		Match(string, string) HandleFunc
		RegisterFunc(string, string, HandleFunc)
	}
	// Server 服務啓動接口
	Server interface {
		ListenAndServe() error
	}
	// Context 請求上下文,封裝請求操做,未詳細實現。
	Context struct {
		*http.Request
		http.ResponseWriter
		Logger
	}
	// MyRouter 基於map和遍歷實現的簡化路由器
	MyRouter struct {
		RoutesConst map[string]HandleFunc
		RoutesPath  []string
		RoutesFunc  []HandleFunc
	}
	// MyLogger 輸出到標準輸出的日誌接口實現
	MyLogger struct {
		out io.Writer
	}
)

// NewApp 函數建立一個app。
func NewApp() *App {
	return &App{
		Addr:   ":8088",
		Logger: &MyLogger{},
		Router: &MyRouter{},
	}
}

// Run 方法啓動App。
func (app *App) Run() error {
	// Server初始化
	if app.Server == nil {
		app.Server = &http.Server{
			Addr:    app.Addr,
			Handler: app,
		}
	}
	app.Printf("start server: %s", app.Addr)
	return app.Server.ListenAndServe()
}

// ServeHTTP 方式實現http.Hander接口,處理Http請求。
func (app *App) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
	ctx := &Context{
		Request:        req,
		ResponseWriter: resp,
		Logger:         app,
	}
	// 路由匹配
	h := app.Router.Match(ctx.Method(), ctx.Path())
	// 處理中間件
	for _, i := range app.Middlewares {
		h = i(h)
	}
	// 處理請求
	h(ctx)
}

// AddMiddleware App增長一個處理中間件。
func (app *App) AddMiddleware(m ...MiddlewareFunc) {
	app.Middlewares = append(app.Middlewares, m...)
}

// Print 方法日誌輸出,實現Logger接口。
func (l *MyLogger) Print(args ...interface{}) {
	if l.out == nil {
		l.out = os.Stdout
	}
	fmt.Print(time.Now().Format("2006-01-02 15:04:05 - "))
	fmt.Fprintln(l.out, args...)
}

// Printf 方法日誌輸出,實現Logger接口。
func (l *MyLogger) Printf(format string, args ...interface{}) {
	l.Print(fmt.Sprintf(format, args...))
}

// Match 方法匹配一個Context的請求,實現Router接口。
func (r *MyRouter) Match(method, path string) HandleFunc {
	// 查找路由
	path = method + path
	h, ok := r.RoutesConst[path]
	if ok {
		return h
	}
	for i, p := range r.RoutesPath {
		if strings.HasPrefix(path, p) {
			return r.RoutesFunc[i]
		}
	}
	return Handle404
}

// Handle404 函數定義處理404響應,沒有找到對應的資源。
func Handle404(ctx *Context) {
	ctx.ResponseWriter.WriteHeader(404)
	ctx.ResponseWriter.Write([]byte("404 Not Found"))
}

// RegisterFunc 方法註冊路由處理函數,實現Router接口。
func (r *MyRouter) RegisterFunc(method string, path string, handle HandleFunc) {
	if r.RoutesConst == nil {
		r.RoutesConst = make(map[string]HandleFunc)
	}
	path = method + path
	if path[len(path)-1] == '*' {
		r.RoutesPath = append(r.RoutesPath, path)
		r.RoutesFunc = append(r.RoutesFunc, handle)
	} else {
		r.RoutesConst[path] = handle
	}
}

// Method 方法獲取請求方法。
func (ctx *Context) Method() string {
	return ctx.Request.Method
}

// Path 方法獲取請求路徑。
func (ctx *Context) Path() string {
	return ctx.Request.URL.Path
}

// RemoteAddr 方法獲取客戶端真實地址。
func (ctx *Context) RemoteAddr() string {
	xforward := ctx.Request.Header.Get("X-Forwarded-For")
	if "" == xforward {
		return strings.SplitN(ctx.Request.RemoteAddr, ":", 2)[0]
	}
	return strings.SplitN(string(xforward), ",", 2)[0]
}

// WriteString 方法實現請求上下文返回字符串。
func (ctx *Context) WriteString(s string) {
	ctx.ResponseWriter.Write([]byte(s))
}

// MiddlewareLoggerFunc 函數實現日誌中間件函數。
func MiddlewareLoggerFunc(h HandleFunc) HandleFunc {
	return func(ctx *Context) {
		ctx.Printf("%s %s %s", ctx.RemoteAddr(), ctx.Method(), ctx.Path())
		h(ctx)
	}
}

func main() {
	app := NewApp()
	app.AddMiddleware(MiddlewareLoggerFunc)
	app.RegisterFunc("GET", "/hello", func(ctx *Context) {
		ctx.WriteString("hello micro web")
	})
	app.Run()
}
複製代碼
相關文章
相關標籤/搜索