发布于 

go-Web框架实现01

go-Web框架实现 | 笔记整理!

day01 | 基础实现

方法绑定 | 参考官方实现

http.HandleFunc | go官方文档

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

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

    1
    2
    3
    4
    5
    6
    // 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结构体进行识别 会发现他的原始是

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    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文档自己实现一个类似的方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    // 处理函数
    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官方文档,不难发现

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    // 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.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    // 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,其中官方文档中的一个实现方式是

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    // 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)
    }
  • 我们为了达到自己实现目的,进行简单的类型匹配~(可以直接简化实现)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// 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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// 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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
// 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