golang

http.Handle和http.HandleFunc的区别

Posted by Liangjf on June 29, 2019

#go http.Handle和http.HandleFunc的区别

例子分析

package main

import (
    "log"
    "io"
    "net/http"
)

type TestHandle struct {}
func (t TestHandle)ServeHTTP(w http.ResponseWriter, r *http.Request)  {
    _, _ = io.WriteString(w, "test1")
}

func TestHttp(w http.ResponseWriter, r *http.Request) {
    _, _ = io.WriteString(w, "test2")
}

func main() {
    testHandle := TestHandle{}
    http.Handle("/test1", testHandle)

    http.HandleFunc("/test2", TestHttp)

    log.Fatal(http.ListenAndServe(":8080", nil).Error())
}

一眼可以看出来,http.Handlehttp.HandleFunc 的区别是,前者需要声明一个结构体,然后实现 ServeHTTP(http.ResponseWriter, *http.Request) 接口。后者直接传入一个 以(whttp.ResponseWriter, *http.Request)为参数的函数指针。

http.Handle的底层调用

http.Handle("/test1", testHandle)

func Handle(pattern string, handler Handler) { DefaultServeMux.Handle(pattern, handler) }

func (mux *ServeMux) Handle(pattern string, handler Handler) {...}

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

可以看到 http.Handle 第二个参数是 Handler,是一个接口结构,所以通过实现接口,调用实例的原理,传进去的结构体只要实现了 ServeHTTP 接口,在 Handle 中就会注册(map结构,key是路由路径,value是实现ServeHTTP接口的结构体),路由响应就会调用对用的响应函数了。

http.HandleFunc的底层调用

http.HandleFunc("/test2", TestHttp)

func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {      
    DefaultServeMux.HandleFunc(pattern, handler)
}

(mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request))

mux.Handle(pattern, HandlerFunc(handler)

type HandlerFunc func(ResponseWriter, *Request)

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

一路看下来,http.HandleFunc 主要是第二个参数是 handler func(ResponseWriter, *Request)。相当于直接把响应函数赋值给 HandlerFuncHandlerFuncfunc(ResponseWriter, *Request) 类型,并且它实现了 ServeHTTP接口,里面会调用f,并且在路由响应时触发注册的响应函数被调用。

总结

因此,整个流程下来,http.Handlehttp.HandleFunc 就是通过不同方式实现一个 ServeHTTP 接口,在路由选中时触发响应的。应用了对象封装,实现接口,多态的特性吧。