HTTP 框架是怎么形成的
标准库的 HTTP 框架
HTTP 框架是后端开发当中最为常见的一种框架, 各种 HTTP 框架虽然看起来不同但是大多数都是采用了 标准库的 API 下面是最为简单的 HTTP 的使用
package main
import (
"net/http"
)
func main() {
http.HandleFunc("/ping",func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Hello, world!"))
w.WriteHeader(http.StatusOK)
})
http.ListenAndServe("0.0.0.0:8080", nil)
}
虽然是最为简单的一种使用方式, 但是却是很多 http 框架的基础。下面是最为简单的利用标准库的 http 来实现一个 自己的 http 框架。
package main
import (
"net/http"
)
type Engine struct{}
// ServeHTTP implements http.Handler.
func (*Engine) ServeHTTP(w http.ResponseWriter,r *http.Request) {
w.Write([]byte(r.Method+r.URL.Path))
}
func main() {
http.ListenAndServe("0.0.0.0:8080", &Engine{})
}
var _ http.Handler = (*Engine)(nil)
可以看到只要把原来的 nil 给替换成已经应用的 http.Handle 接口的 engine,这样就可以把用户的方法的请求 URL 给打印出来。这就是最为简单的一个 HTTP 应用
简单的 map 注册路由
一个 HTTP 框架单单只是打印方法和 URL 还不够,必须注册路由和处理函数。要实现这个路由功能最为简单的就是用 map 实现。实现起来性能很高但是缺点就是不能支持动态路由
func (e *Engine) ServeHTTP(w http.ResponseWriter,r *http.Request) {
key := r.Method + "-" + r.URL.Path
if handler,ok:=e.router[key];ok {
handler(w,r)
}
}
使用前缀树注册路由
要实现一个动态路由那么久必须使用前缀树来对路由进行匹配。这种路由的实现方式比较复杂,有兴趣的可以看看gin的源码。其主要作用就是对:user和通配符做了处理使得框架可以匹配动态路由。
中间件的执行
http框架必须要有能够处理中间件的能力,但是go当中的框架中间件是递归执行的使用过程当中必须手动执行c.Next()这就造成了代码执行顺序不一致。比如在第一个执行的c.Next()的中间件当中之前代码最先执行之后的代码最后执行。