为什么需要gin框架而不用传统的内置的net/http包?
因为net/http包提供了基础的web功能,即监听端口、静态路由、解析http报文,但是一些web开发中的基础功能并不支持,需要手工实现。例如:
- 动态路由: hello/:name , hello/* 这类规则
- 鉴权:没有分组/统一鉴权的能力,需要在每个路由映射的handler中实现。
- 模板:没有统一简化的HTML机制。
- ....
传统net/http实现
func HelloServer(w http.ResponseWriter,req *http.Request) {
fmt.Println("Inside HelloServer handler")
// req.FormValue("val") //获取post请求中的表单 val对应的值
fmt.Fprintf(w,"hello,"+req.URL.Path[1:]) // req.URL.Path[1:] 表示丢弃路径中的/ 截取路径中/后的字符串
// io.WriteString(w,"hello,"+req.URL.Path[1:])
title := "简单服务器"
fmt.Fprintf(w, "<h1>%s</h1><div>%s</div>", title, req.URL.Path[1:])
}
func main() {
//路径前缀匹配 匹配路径以/开头的请求
http.HandleFunc("/",HelloServer)
err := http.ListenAndServe("localhost:8080",nil)
if err != nil {
log.Fatal("ListenAndServer",err.Error())
}
}
上面的代码中我们定义了一个路由以及对应路由的handler,main函数中监听8080端口,用来启动web服务,当我们访问该路由就会转到对应的处理器。ListenAndServe方法中两个参数第一个是监听的端口,第二是处理所有http请求的实例,当为空的时候就会使用标准库的实例处理,就是上面对应的每个路由对应的handler。
type Handler interface { ServeHTTP(ResponseWriter, *Request) }
点开发现第二个参数是一个接口,有一个servehttp方法,只要实现了该接口的实例都可以传入上面的函数,这时所有的http请求都会转入该实例由该实例进行实现。这是实现web框架的入口。
type Engine struct{}
func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) {
switch req.URL.Path {
case "/":
fmt.Fprintf(w, "URL,PATH=%q\n", req.URL.Path)
case "/heelo":
for k, v := range req.Header {
fmt.Fprintf(w, "Header[%q] = %q\n", k, v)
}
default:
fmt.Fprintf(w, "404 NOT FOUND: %s\n", req.URL)
}
}
func main() {
engine := new(Engine)
http.ListenAndServe(":8080", engine)
}
上述是简单的自定义处理实例的一个实现,会发现监听8080端口后,所有请求都转入engine中的servehttp中处理。 对比用net\http包中的处理来说,自定义处理逻辑拦截了所有的http请求,在其中可以定义路由的映射逻辑和实现一些事务处理,而标准库只能实现一些静态路由。
自定义http请求处理实现静态路由
type HandlerFunc func(w http.ResponseWriter, req *http.Request)
type Engine struct {
router map[string]HandlerFunc //存储路由映射到具体的handler
}
func New() *Engine {
return &Engine{
router: make(map[string]HandlerFunc),
}
}
func (engine *Engine) addRoute(method, pattern string, handlerFunc HandlerFunc) {
key := method + "-" + pattern
engine.router[key] = handlerFunc
}
func (engine *Engine) GET(pattern string, handlerFunc HandlerFunc) { //注册GET路由
engine.addRoute("GET", pattern, handlerFunc)
}
func (engine *Engine) POST(pattern string, handlerFunc HandlerFunc) { //注册GET路由
engine.addRoute("POST", pattern, handlerFunc)
}
func (engine *Engine) Run(addr string) { //对listenandserve的包装 启动服务器监听
err := http.ListenAndServe(addr, engine)
if err != nil {
log.Fatal("监听端口失败", err)
}
}
//实现servehttP方法 一切请求转入该方法执行
func (engine *Engine) ServeHTTP(w http.ResponseWriter, r *http.Request) {
key := r.Method + "-" + r.URL.Path
if handler, ok := engine.router[key]; ok {
handler(w, r) //根据不同的请求转入相应的处理方法 --已经注册的路由,未注册返回404
} else {
fmt.Fprintf(w, "404 NOT FOUND %s\n", r.URL)
}
}
main 中进行调用
r := gee.New()
r.GET("/hello", func(w http.ResponseWriter, req *http.Request) {
fmt.Fprintf(w, "hello world")
})
r.Run(":8080")