首页

Go web标准库中的处理器与处理器函数

Go语言的标准库就足够实现非常强大的web开发,通过net/http标准库,我们可以启动一个HTTP服务器,然后让这个服务器接收请求并向请求返回响应,而接收服务器请求靠的就是处理器。看一个完整的例子,它包括处理器和处理器函数:
    package main

    import (
        "fmt"
        "net/http"
    )

    // 处理器
    type HelloHandler struct{}

    func (h *HelloHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintf(w, "Hello, v1!")
    }

    // 处理器函数
    func hellov2(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintf(w, "Hello, v2!")
    }

    func main() {
        hello := HelloHandler{}

        server := http.Server{
            Addr: "127.0.0.1:8080",
        }

        http.Handle("/hellov1", &hello)
        http.HandleFunc("/hellov2", hellov2)

        server.ListenAndServe()
    }

在Go语言中,一个处理器就是一个拥有ServeHTTP方法的接口:
只要实现这个接口,都是处理器
    type Handler interface {
        ServeHTTP(ResponseWriter, *Request)
    }

当我们在代码用使用处理器,它底层代码是如何执行的呢?
  http.Handle("/hellov1", &hello)

第一步:它直接就调用到http包里面的Handle函数
  func Handle(pattern string, handler Handler) { DefaultServeMux.Handle(pattern, handler) }

第二步:DefaultServeMux多路复用器是ServeMux结构的一个实例,所以它其实调用底层的ServeMux的Handle方法
  func (mux *ServeMux) Handle(pattern string, handler Handler)

处理器函数实际上就是与处理器拥有相同行为的函数,这些函数与ServeHTTP方法拥有相同的签名。让我们来一步一步看看源码,就更加清晰它的底层实现了:
当我们在代码中使用处理器函数,它的底层代码是如何执行的呢?
  http.HandleFunc("/hellov2", hellov2)

第一步:DefaultServeMux多路复用器是ServeMux结构的一个实例
    func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
        DefaultServeMux.HandleFunc(pattern, handler)
    }

第二部:这里就更加明显,调用Handle方法,调用前首先执行转换
    func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
        if handler == nil {
            panic("http: nil handler")
        }
        mux.Handle(pattern, HandlerFunc(handler))
    }

第三步:HandlerFunc不仅仅是一个函数类型,还拥有自己的方法,也满足接口http.Handler
    type HandlerFunc func(ResponseWriter, *Request)

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

第四步:不管是处理器还是处理器函数,它们最终都是调用ServeMux的Handle方法
  func (mux *ServeMux) Handle(pattern string, handler Handler)

总结:使用处理器函数可以使得代码更加简洁,但是我们在某些情况下,使用处理器更加好的扩充以及灵活性。处理器与处理器函数的区别,关键是要理解Go语言接口和函数类型的妙用。
from 爱施园
Posted by 森林 on 2019/01/15
Copyright ©2018 爱施园 粤ICP备14091834号