Go 实现简易web框架

用 Go 实现一个 http server 非常容易,Go 语言标准库 net/http 自带了一系列结构和方法来帮助开发者简化 HTTP 服务开发的相关流程。因此,我们不需要依赖任何第三方组件就能构建并启动一个高并发的 HTTP 服务器。

基于 HTTP 构建的服务标准模型包括两个端,客户端 (Client) 和服务端 (Server)。HTTP 请求从客户端发出,服务端接受到请求后进行处理然后将响应返回给客户端。所以 http 服务器的工作就在于如何接受来自客户端的请求,并向客户端返回响应。

Demo1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package main

import (
"fmt"
"net/http"
)

func HelloHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello World")
}

func main () {
http.HandleFunc("/", HelloHandler)
http.ListenAndServe(":8080", nil)
}

Demo2

实现ServeHTTP方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package main

import (
"fmt"
"net/http"
)

type HelloHandlerStruct struct {
content string
}

func (handler *HelloHandlerStruct) ServeHTTP(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, handler.content)
}

func main() {
http.Handle("/", &HelloHandlerStruct{content: "Hello World"})
http.ListenAndServe(":8000", nil)
}

我们查看net/http包可以看到Handler的定义

1
2
3
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}

定义一个类型,实现ServeHTTP方法,这个类型可以是一个func类型

1
2
3
4
5
6
type HandlerFunc func(ResponseWriter, *Request)

// ServeHTTP calls f(w, r).
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
f(w, r)
}

通过反射调用func

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
type Handle func(w http.ResponseWriter, r *http.Request)

type Router struct {
paths map[string]Handle
}

//register handle
func (r *Router) AddPath(path string, controller Handle) {
if r.paths == nil {
r.paths = map[string]Handle{}
}
paths := r.paths
paths[path] = controller
r.paths = paths
}

func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
if handle, ok := r.paths[req.URL.Path]; ok {
handle(w, req)
} else {
//method not register

w.WriteHeader(http.StatusInternalServerError)
err := fmt.Errorf("method %s is not found", req.URL.Path)
w.Write([]byte(err.Error()))

}
}

注册handle

1
r.AddPath("/hello", Action((*controllers.HelloController).Hello))

通过反射,动态调用handle

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
// 反射执行方法调用
func Action(action interface{}) Handle {
val := reflect.ValueOf(action)
if val.Kind() != reflect.Func {
panic("action not func")
}
t := val.Type()

//确保方法返回参数为error
out := t.Out(0)
if !out.Implements(interfaceOf((*error)(nil))) {
fmt.Println("Action return not error")
}

t = t.In(0)
for t.Kind() == reflect.Ptr {
t = t.Elem()
}
// 确保
if !reflect.PtrTo(t).Implements(interfaceOf((*controllers.Controller)(nil))) {
panic("not implement controller")
}

return func(w http.ResponseWriter, r *http.Request) {
v := reflect.New(t)

//反射获取controller
c := v.Interface().(controllers.Controller)
//init
err := c.Init(w, r)
defer c.Destroy()
if err != nil {
c.Error(err)
return
}
//反射调用方法
ret := val.Call([]reflect.Value{v})[0].Interface()
//fmt.Println(reflect.TypeOf(ret))
if ret != nil {
c.Error(ret.(error))
return
}
}
}

func interfaceOf(value interface{}) reflect.Type {
t := reflect.TypeOf(value)

for t.Kind() == reflect.Ptr {
t = t.Elem()
}

return t
}

源码https://github.com/pangxieke/simple

复杂框架

上面的框架组件基本自己开发,但现在已经有很多完善的组件,我们只要好好利用,就可以开发出适合自己的框架。

例如logger,router等都不需要自己开发

自己将常用的框架文件,config配置,数据库连接等集合在一起,组成了一个工作中实际可用的框架。

源码https://github.com/pangxieke/portray

参考文章

Go Web 编程入门–深入学习用 Go 编写 HTTP 服务器]

螃蟹 wechat
欢迎您扫一扫上面的微信公众号,订阅我的博客!
坚持原创技术分享,您的支持将鼓励我继续创作!