TreeviewCopyright © aleen42 all right reserved, powered by aleen42
在入门里面我们直接通过http.ListenAndServe(":8080", nil)的方式直接启动,但这样实现毕竟太简单,如果想做更负责的分发 就可以自己去实现 如果深入看一下这个方法就可以发现
func ListenAndServe(addr string, handler Handler) error {
server := &Server{Addr: addr, Handler: handler}
return server.ListenAndServe()
}
这个方法接受传参handler,那么handler是什么呢?
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}
就是一个实现了http请求并返回的接口,那么是不是任何实现了这个接口的都可以呢?答案是肯定的 下面举个例子
package main
import (
"fmt"
"net/http"
)
// 创建一个 foo 类型
type foo struct {}
// 为 foo 类型创建 ServeHTTP 方法,以实现 Handle 接口
func (f foo) ServeHTTP(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "Implement the Handle interface.")
}
func main() {
// 创建对象,类型名写后面..
var f foo
http.ListenAndServe(":8080",f)
}
启动并测试
$ curl 127.0.0.1:8080
Implement the Handle interface.
那么如果你想实现更加复杂的路由,都可以在ServeHTTP这个方法里面去实现了,譬如下面这个例子
package main
import (
"fmt"
"net/http"
)
// 创建一个 foo 类型
type foo struct {}
// 为 foo 类型创建 ServeHTTP 方法,以实现 Handle 接口
func (f foo) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// 根据 URL 的相对路径来设置网页内容(不优雅)
switch r.URL.Path {
case "/boy":
fmt.Fprintln(w, "I love you!!!")
case "/girl":
fmt.Fprintln(w, "hehe.")
default:
fmt.Fprintln(w, "Men would stop talking and women would shed tears when they see this.")
}
}
func main() {
// 创建对象,类型名写后面..
var f foo
http.ListenAndServe(":8080",f)
}
这通通过url path去判断该使用哪条路由,测试一下:
$ curl 127.0.0.1:8080/boy
I love you!!!
$ curl 127.0.0.1:8080/girl
hehe.
$ curl 127.0.0.1:8080
Men would stop talking and women would shed tears when they see this.
如果你认为实现不够优雅可以通过http.NewServeMux() 优化,
package main
import (
"fmt"
"net/http"
)
type boy struct{}
func (b boy) ServeHTTP(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "I love you!!!")
}
type girl struct{}
func (g girl) ServeHTTP(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "hehe.")
}
type foo struct{}
func (f foo) ServeHTTP(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "Men would stop talking and women would shed tears when they see this.")
}
func main() {
var b boy
var g girl
var f foo
// 返回一个 *ServeMux 对象
mux := http.NewServeMux()
mux.Handle("/boy/", b)
mux.Handle("/girl/", g)
mux.Handle("/", f)
http.ListenAndServe(":8080", mux)
}
深入理解
HandleFunc
HandleFunc需要传入的是一个函数
handler func(ResponseWriter, *Request)
并把它放到DefaultServeMux里面,二所谓的HandlerFunc就是这个方法的别名
type HandlerFunc func(ResponseWriter, *Request)
所以如果想实现级联就只需要对原理的方法进行包装就可以了,譬如
http.HandleFunc("/say",NeedLogin(say))
...
func NeedLogin(h http.HandlerFunc) http.HandlerFunc{
return func(w http.ResponseWriter, r *http.Request) {
fmt.Println("get request")
h(w,r)
}
}
这样就可以在线执行NeedLogin方法了,上面的h就是say。执行完NeedLogin再去执行h方法。
Handle
http.ListenAndServe(":9999",r)
这个方法需要传入的是Handler,而Handler又是什么呢?它是一个接口,实现了ServeHTTP的一个接口
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}
那么只要是实现了它的接口都可以放入,上文已经举例说明了
那么如果你想实现级联,同样可以
type Counter struct {
count map[string]int
h http.Handler
}
func NewCounter(h http.Handler) *Counter{
return &Counter{
h :h,
count: make(map[string]int ),
}
}
func (c *Counter)ServeHTTP(w http.ResponseWriter, r *http.Request){
c.count[r.URL.Path]++
c.h.ServeHTTP(w,r)
}
//----------------------------------------------//
type Recorder struct {
h http.Handler
}
func NewRecoder(h http.Handler) *Recorder{
return &Recorder{
h :h,
}
}
func (c *Recorder)ServeHTTP(w http.ResponseWriter, r *http.Request){
fmt.Println("record ", r.URL.Path)
c.h.ServeHTTP(w,r)
}
//------------------------------------------------//
//h := handlers.LoggingHandler(os.Stderr,http.DefaultServeMux)
c := NewCounter(http.DefaultServeMux)//this switch http.DefaultServeMux to h is ok,add log feature
r := NewRecoder(c)
http.ListenAndServe(":9999",r)
上面通过层层包装先是NewCounter、然后NewRecoder,这样在调用9999端口的这个服务的时候都会先执行上面两个方法