go web示例
我们以下面的示例介绍golang的net/http
包的简单使用。
package main
import "net/http"
func main() {
http.HandleFunc("/", helloWord) // 注册处理器
http.ListenAndServe(":8888", nil) // 监听8888端口,启动web项目
}
func helloWorld(rw http.ResponseWriter, r *http.Request) {
rw.Write([]byte("Hello, World!"))
}
http.HandleFunc
http.HandleFunc
在DefaultServeMux
中注册一个handler。
DefaultServeMux
是go默认提供的ServeMux
。
// HandleFunc registers the handler function for the given pattern
// in the DefaultServeMux.
// The documentation for ServeMux explains how patterns are matched.
func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
DefaultServeMux.HandleFunc(pattern, handler)
}
DefaultServeMux
:
当我们没有创建ServeMux变量时,会使用这个默认创建的。
// DefaultServeMux is the default ServeMux used by Serve.
var DefaultServeMux = &defaultServeMux
var defaultServeMux ServeMux
ServeMux
ServeMux 是一个http请求的多路复用器。从请求路径到handler的映射全部存在一个map数据类型的属性里,即ServeMux.m
。
// ServeMux 是一个http请求的多路复用器.
type ServeMux struct {
mu sync.RWMutex
m map[string]muxEntry
es []muxEntry // contains all patterns that end in / sorted from longest to shortest.
hosts bool // whether any patterns contain hostnames
}
type muxEntry struct {
h Handler
pattern string
}
我们接着看上一节中的DefaultServeMux.HandleFunc(pattern, handler)
方法:
该方法将路径及相应的处理器注册进ServeMux中。
// HandleFunc registers the handler function for the given pattern.
func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
if handler == nil {
panic("http: nil handler")
}
mux.Handle(pattern, HandlerFunc(handler))
}
// Handle registers the handler for the given pattern.
// If a handler already exists for pattern, Handle panics.
func (mux *ServeMux) Handle(pattern string, handler Handler) {
mux.mu.Lock()
defer mux.mu.Unlock()
if pattern == "" {
panic("http: invalid pattern")
}
if handler == nil {
panic("http: nil handler")
}
if _, exist := mux.m[pattern]; exist {
panic("http: multiple registrations for " + pattern)
}
if mux.m == nil {
mux.m = make(map[string]muxEntry)
}
e := muxEntry{
h: handler, pattern: pattern}
mux.m[pattern] = e
if pattern[len(pattern)-1] == '/' {
mux.es = appendSorted(mux.es, e)
}
if pattern[0] != '/' {
mux.hosts = true
}
}
同时,ServeMux还实现了Handler接口:
Handler接口仅定义了一个ServeHTTP(ResponseWriter, *Request)
方法,用来响应http请求。ServeMux实现了该方法,其主要作用是分发http请求给相应的handler。
// A Handler responds to an HTTP request.
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}
// ServeHTTP dispatches the request to the handler whose
// pattern most closely matches the request URL.
func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request) {
if r.RequestURI == "*" {
if r.ProtoAtLeast(1, 1) {
w.Header().Set("Connection", "close")
}
w.WriteHeader(StatusBadRequest)
return
}
h, _ := mux.Handler(r)
h.ServeHTTP(w, r)
}
在上面的代码中,mux.handler(r)
会根据请求中的url查找出handler,例如:通过路径/
找到helloWorld
函数。
而在下一行代码h.ServeHTTP(w, r)
,函数会调用ServeHTTP方法来处理请求。因为在go中处理请求的统一方法是ServeHTTP(ResponseWriter, *Request)
,即必须实现handler接口。
其实在上面的注册步骤中,有这样一个语句mux.Handle(pattern, HandlerFunc(handler))
。第二个参数HandlerFunc(handler)
的作用是将我们写的请求处理函数(例如:helloWord(rw http.ResponseWriter, r *http.Request)
)强制转换成HandlerFunc
类型。HandlerFunc
定义如下:
// The HandlerFunc type is an adapter to allow the use of
// ordinary functions as HTTP handlers. If f is a function
// with the appropriate signature, HandlerFunc(f) is a
// Handler that calls f.
type HandlerFunc func(ResponseWriter, *Request)
// ServeHTTP calls f(w, r).
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
f(w, r)
}
HandlerFunc也实现了ServeHTTP方法,因此也是Handler接口的实现,我们可以看到这个实现本质上是对开发者所写的函数进行封装,以符合golang对于请求处理的规范。
所以,灵活地运用Handler
接口,也可以帮助我们写出一些filter等web中间件。
ListenAndServe
熟悉tcp编程的,其实理解 ListenAndServe
过程很容易。其过程大体就是监听指定地址,等待请求,请求进来后解析报文并调用相应的handler。这里不再详细描述。
我们可以注意到,在最开始的示例中,ListenAndServe的第二参数是nil。在这种情况下,当请求进来后就会默认使用DefaultServeMux 。
// ListenAndServe listens on the TCP network address addr and then calls
// Serve with handler to handle requests on incoming connections.
// Accepted connections are configured to enable TCP keep-alives.
//
// The handler is typically nil, in which case the DefaultServeMux is used.
//
// ListenAndServe always returns a non-nil error.
func ListenAndServe(addr string, handler Handler) error {
server := &Server{
Addr: addr, Handler: handler}
return server.ListenAndServe()
}