对于GO中的HTTP内置包,有一些需要避坑的点,博主写在另一篇文章中,那篇文章中需要避免的坑对我们在设计自己的Web框架有很大的好处,尤其是对于上下文。
启动服务
方式一
package main
import "net/http"
func main() {
// 将路由和视图函数进行绑定
http.HandleFunc("/user", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte("user home"))
})
// 启动服务器,第二个参数是nil表示用net/http内置的默认的IO多路复用器
_ = http.ListenAndServe(":8080", nil)
}
方式二
package main
import "net/http"
func main() {
// 初始化一个复用器
mux := http.NewServeMux()
mux.HandleFunc("/user", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte("user home"))
})
http.Handle("/user", mux)
_ = http.ListenAndServe(":8080", mux)
}
方式三
我们由方式二得出灵感,自定义一个结构体实现Handler接口就能充当一个IO多路复用器。并且Handler接口要求需要实现ServeHTTP方法即可。
package main
import (
"fmt"
"net/http"
)
type Engine struct{}
func (e *Engine) ServeHTTP(w http.ResponseWriter, r *http.Request) {
url := r.URL.Path
switch url {
case "/user":
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte(fmt.Sprintf("hello %s", url)))
case "/order":
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte(fmt.Sprintf("hello %s", url)))
default:
w.WriteHeader(http.StatusNotFound)
_, _ = w.Write([]byte("NOT FOUND"))
return
}
}
func NewEngine() *Engine {
return &Engine{}
}
func main() {
engine := NewEngine()
_ = http.ListenAndServe(":8080", engine)
}
框架雏形
在具体实现neo框架雏形的时候,我们需要先思考几个问题。【可以对比Gin框架】
- 路由存在什么地方
- 路由怎么注册
- 路由怎么匹配
- Web服务怎么启动
- Web服务支持那些请求方式
package neo
import (
"fmt"
"net/http"
)
// HandlerFunc 视图函数签名
type HandlerFunc func(w http.ResponseWriter, r *http.Request)
type Engine struct {
router map[string]HandlerFunc // 路由和视图作绑定【key是路由,value是视图函数】
}
// 内部核心API,仅共内部使用,用于注册路由
func (e *Engine) addRouter(method string, pattern string, handlerFunc HandlerFunc) {
key := fmt.Sprintf("%s-%s", method, pattern)
e.router[key] = handlerFunc
}
// GET 外部衍生API,提供给用户使用
func (e *Engine) GET(pattern string, handlerFunc HandlerFunc) {
e.addRouter(http.MethodGet, pattern, handlerFunc)
}
func (e *Engine) POST(pattern string, handlerFunc HandlerFunc) {
e.addRouter(http.MethodPost, pattern, handlerFunc)
}
func (e *Engine) DELETE(pattern string, handlerFunc HandlerFunc) {
e.addRouter(http.MethodDelete, pattern, handlerFunc)
}
func (e *Engine) PUT(pattern string, handlerFunc HandlerFunc) {
e.addRouter(http.MethodPut, pattern, handlerFunc)
}
// 对外对接用户,对内对接Web框架
func (e *Engine) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// 请求来了,需要匹配路由
url := r.URL.Path
method := r.Method
key := fmt.Sprintf("%s-%s", method, url)
handlerFunc, ok := e.router[key]
if !ok {
w.WriteHeader(http.StatusNotFound)
_, _ = w.Write([]byte("NOT FOUND"))
return
}
// 执行命中的视图函数
handlerFunc(w, r)
}
// Run 手动启动服务,控制力强
func (e *Engine) Run(addr string) error {
return http.ListenAndServe(addr, e)
}
func New() *Engine {
return &Engine{router: make(map[string]HandlerFunc)}
}