day01 | 基础实现 | web框架 | 笔记心得

93 阅读4分钟

方法绑定 | 参考官方实现

http.HandleFunc | go官方文档

  • 会传入两个参数 | 匹配模式和处理方法 然后交给DefaultServeMuxHandleFunc函数来实现模式匹配处理

  • 其中这个 DefaultServeMuxgo官方实现的 需要我们自己进行重现一下

    // HandleFunc registers the handler function for the given pattern
    // in the DefaultServeMux.
    // The documentation for ServeMux explains how patterns are matched.
    func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
        DefaultServeMux.HandleFunc(pattern, handler)
    }
    
  • 其中我们对于DefaultServeMux结构体进行识别 会发现他的原始是

    type ServeMux struct {
    	mu    sync.RWMutex
    	m     map[string]muxEntry
    	es    []muxEntry // slice of entries sorted from longest to shortest.
    	hosts bool       // whether any patterns contain hostnames
    }
    
    type muxEntry struct {
    	h       Handler
    	pattern string
    }
    
    // DefaultServeMux is the default ServeMux used by Serve.
    var DefaultServeMux = &defaultServeMux
    
    var defaultServeMux ServeMux
    
  • 我们自己可以仿照go文档自己实现一个类似的方法

    // 处理函数
    type HandleFunc func(http.ResponseWriter, *http.Request)
    
    // 官方实现的 比较全面 <-自己来手动写一个 基础的
    //type ServeMux struct {
    //	mu    sync.RWMutex
    //	m     map[string]muxEntry
    //	es    []muxEntry // slice of entries sorted from longest to shortest.
    //	hosts bool       // whether any patterns contain hostnames
    //}
    //
    //type muxEntry struct {
    //	h       Handler
    //	pattern string
    //}
    
    type Engine struct {
    	router map[string]HandleFunc
    }
    
    func New() *Engine {
    	return &Engine{router: make(map[string]HandleFunc)}
    }
    
    // 内部使用的
    func (engine *Engine) addRounte(method string, pattern string, handler HandleFunc) {
    	key := method + "-" + pattern
    	engine.router[key] = handler
    }
    
    // get方法实现
    func (engine *Engine) GET(pattern string, handler HandleFunc) {
    	engine.addRounte("GET", pattern, handler)
    }
    
    // post方法实现
    func (engine *Engine) POST(pattern string, handler HandleFunc) {
    	engine.addRounte("POST", pattern, handler)
    }
    
    // run 开始运行
    func (engine *Engine) Run(addr string) (err error) {
    	return http.ListenAndServe(addr, engine)
    }
    

ListenAndServe | 参数接口实现

  • 查看go官方文档,不难发现

    // ListenAndServe listens on the TCP network address addr and then calls
    // Serve with handler to handle requests on incoming connections.
    // Accepted connections are configured to enable TCP keep-alives.
    //
    // The handler is typically nil, in which case the DefaultServeMux is used.
    //
    // ListenAndServe always returns a non-nil error.
    func ListenAndServe(addr string, handler Handler) error {
    	server := &Server{Addr: addr, Handler: handler}
    	return server.ListenAndServe()
    }
    
  • 其中有一个参数是 handler类型是Handler.

    // A Handler responds to an HTTP request.
    //
    // ServeHTTP should write reply headers and data to the ResponseWriter
    // and then return. Returning signals that the request is finished; it
    // is not valid to use the ResponseWriter or read from the
    // Request.Body after or concurrently with the completion of the
    // ServeHTTP call.
    //
    // Depending on the HTTP client software, HTTP protocol version, and
    // any intermediaries between the client and the Go server, it may not
    // be possible to read from the Request.Body after writing to the
    // ResponseWriter. Cautious handlers should read the Request.Body
    // first, and then reply.
    //
    // Except for reading the body, handlers should not modify the
    // provided Request.
    //
    // If ServeHTTP panics, the server (the caller of ServeHTTP) assumes
    // that the effect of the panic was isolated to the active request.
    // It recovers the panic, logs a stack trace to the server error log,
    // and either closes the network connection or sends an HTTP/2
    // RST_STREAM, depending on the HTTP protocol. To abort a handler so
    // the client sees an interrupted response but the server doesn't log
    // an error, panic with the value ErrAbortHandler.
    type Handler interface {
    	ServeHTTP(ResponseWriter, *Request)
    }
    
  • 而这是一个interface类型的 需要我们来实现其中的方法ServeHTTP,其中官方文档中的一个实现方式是

    // ServeHTTP dispatches the request to the handler whose
    // pattern most closely matches the request URL.
    func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request) {
    	if r.RequestURI == "*" {
    		if r.ProtoAtLeast(1, 1) {
    			w.Header().Set("Connection", "close")
    		}
    		w.WriteHeader(StatusBadRequest)
    		return
    	}
    	h, _ := mux.Handler(r)
    	h.ServeHTTP(w, r)
    }
    
  • 我们为了达到自己实现目的,进行简单的类型匹配~(可以直接简化实现)

    func (engine *Engine) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    	switch r.URL.Path {
    	case "/":
    		fmt.Fprintf(w, "URL.Path = %q\n", r.URL.Path)
    	case "/hello":
    		for k, v := range r.Header {
    			fmt.Fprintf(w, "Header[%q] = %q\n", k, v)
    		}
    	default:
    		fmt.Fprintf(w, "404 NOT FOUND: %s \n", r.URL)
    	}
    }
    
    

区别对待参考 | 系统 + 自己 | 完整代码!

原本
  • //main.go
// main.go
package main

import (
	"fmt"
	"log"
	"net/http"
)

func main() {
	http.HandleFunc("/", indexHandler)
	http.HandleFunc("/hello", helloHandler)
	log.Fatal(http.ListenAndServe(":9999", nil))
}

// indexHandler
func indexHandler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "URL.Path ==%q\n", r.URL.Path)
}
// hellohandler
func helloHandler(w http.ResponseWriter, r *http.Request) {
	for k, v := range r.Header {
		fmt.Fprintf(w, "Header[%q] = %q\n", k, v)
	}
}
自己实现
  • // base3/main.go
// base3/main.go
package main

import (
	"fmt"
	"net/http"
	"yasuo" // 自己写的模块
)

func main() {
	r := yasuo.New()
	r.GET("/", indexHandler)
	r.GET("/hello", helloHandler)
	r.Run(":9999")
}

// indexHandler 此处为空函数也是可以 因为匹配结果处理  ServeHTTP 已经实现
func indexHandler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "URL.Path ==%q\n", r.URL.Path)
}

// hellohandler 理由同上!
func helloHandler(w http.ResponseWriter, r *http.Request) {
	for k, v := range r.Header {
		fmt.Fprintf(w, "Header[%q] = %q\n", k, v)
	}
}
  • // base3/yasuo/yasuo.go
// base3/yasuo/yasuo.go
package yasuo

import (
	"fmt"
	"net/http"
)

// 处理函数
type HandleFunc func(http.ResponseWriter, *http.Request)

// 官方实现的 比较全面 <-自己来手动写一个 基础的
//type ServeMux struct {
//	mu    sync.RWMutex
//	m     map[string]muxEntry
//	es    []muxEntry // slice of entries sorted from longest to shortest.
//	hosts bool       // whether any patterns contain hostnames
//}

//type muxEntry struct {
//	h       Handler
//	pattern string
//}

type Engine struct {
	router map[string]HandleFunc
}

func New() *Engine {
	return &Engine{router: make(map[string]HandleFunc)}
}

// 内部使用的
func (engine *Engine) addRounte(method string, pattern string, handler HandleFunc) {
	key := method + "-" + pattern
	engine.router[key] = handler
}

// get方法实现
func (engine *Engine) GET(pattern string, handler HandleFunc) {
	engine.addRounte("GET", pattern, handler)
}

// post方法实现
func (engine *Engine) POST(pattern string, handler HandleFunc) {
	engine.addRounte("POST", pattern, handler)
}

// run 开始运行
func (engine *Engine) Run(addr string) (err error) {
	return http.ListenAndServe(addr, engine)
}

// 因为 http.ListenAndServe 第二个参数是 handle是一个接口 接口实现了ServeHTTP
// 需要我们自己来实现一下 ServeHTTP
//
//	type Handler interface {
//		ServeHTTP(ResponseWriter, *Request)
//	}
func (engine *Engine) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	switch r.URL.Path {
	case "/":
		fmt.Fprintf(w, "URL.Path = %q\n", r.URL.Path)
	case "/hello":
		for k, v := range r.Header {
			fmt.Fprintf(w, "Header[%q] = %q\n", k, v)
		}
	default:
		fmt.Fprintf(w, "404 NOT FOUND: %s \n", r.URL)
	}
	mt := "GET" + "-" + r.URL.Path
	fmt.Println(engine.router[r.URL.Path], mt, engine.router[mt])
}

附录 | 参考 | 好文

  1. 七天动手实现go-web框架
  2. 官方文档
  3. 微信读书中go开发实战
  4. go框架-Ez