package main

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

type httpServer struct { }

func (server httpServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {

fmt.Println("------------------")
r.ParseForm()       //解析参数,默认是不会解析的
fmt.Println(r.Form) // 这些信息是输出到服务器端的打印信息
fmt.Println("path:", r.URL.Path)
fmt.Println("scheme:", r.URL.Scheme)
fmt.Println(r.Form["url_ long"])
for k, v := range r.Form {
   fmt.Println("key:", k)
   fmt.Println("val:", strings.Join(v, ""))
}
fmt.Fprintf(w, "Hello GoWeb!") //这个写入到w的是输出到客户端的

}

func main() { var server httpServer // Handle 方法设置访问的路由 http.Handle("/test", server)

// 使用HandleFunc设置访问的路由 http.HandleFunc("/demo", func(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "hello word") //这个写入到w的是输出到客户端的 })

// 设置监听的端口 err := http.ListenAndServe(":7070", nil)

if err != nil { log.Fatal(err) }

} 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. 41. 42. 43. 44. 45.

// 如果路由表中的路径是不以下划线结尾的 /test //那么只有请求路径为/test 完全匹配时才符合 //如果路由表中的注册路径是以下划线结尾的 /test/ //那么请求路径只要满足/test/* 就符合该路由 看看函数: http.Handle("/test", server)

// 函数签名

func Handle(pattern string, handler Handler) { // 下面这个方法我们一会回过头来看 DefaultServeMux.Handle(pattern, 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) 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 看看形参: Handler

// 原来形参是一个interface,那就是我们只要实现了这个签名的类型都可以接收,而httpServer刚好实现了这个签名 type Handler interface { ServeHTTP(ResponseWriter, *Request) } 1. 2. 3. 4. 再看看: ServeHTTP(ResponseWriter, *Request)

HTTP 响应报文结构

感兴趣的看看

// 是处理器用来创建 HTTP 响应的接口,对应着下边的图片看

// 注意、注意、注意 ,这只是个接口,它的执行肯定有一个实现类型,这个我们不展开,下来感兴趣的最好去看一下 type ResponseWriter interface { // 写入返回的状态码 WriteHeader(statusCode int) // 写入返回的消息头 Header() Header // 写入返回的消息体 Write([]byte) (int, error)

} 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 看看:http.Requests

HTTP 请求报文结构

感兴趣的看看

type Request struct { Method string

URL *url.URL
Proto      string // "HTTP/1.0"
ProtoMajor int    // 1
ProtoMinor int    // 0
Header Header
Body io.ReadCloser
ContentLength int64
TransferEncoding []string
Close bool
Host string
Form url.Values
PostForm url.Values
MultipartForm *multipart.Form
....
ctx context.Context

} 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. URL Header Body HTTP的url请求格式为scheme://[userinfo@]host/path[?query][#fragment], go的提供了一个URL结构,用来映射HTTP的请求URL。

type URL struct { Scheme string Opaque string User *Userinfo Host string Path string RawQuery string Fragment string } 1. 2. 3. 4. 5. 6. 7. 8. 9. URL的格式比较明确,其实更好的名词应该是URI,统一资源定位。url中比较重要的是查询字符串query。通常作为get请求的参数。query是一些使用&符号分割的key1=value1&key2=value2键值对,由于url编码是ASSIC码,因此query需要进行urlencode。go可以通过request.URI.RawQuery读取query

小结: 我们现在明白了http.Handle函数的参数 再看看: DefaultServeMux.Handle(pattern, handler)

// 这里面路由表是比较重要的,我们具体分析下http.Server是如何做路由的。 // 路由表实际上是一个map type ServeMux struct { mu sync.RWMutex // key是路径 ==> “/hello” // value是该路径所对应的处理函数 ==> HelloServer m map[string]muxEntry es []muxEntry // slice of entries sorted from longest to shortest. hosts bool // whether any patterns contain hostnames }

// NewServeMux allocates and returns a new ServeMux. func NewServeMux() *ServeMux { return new(ServeMux) }

// DefaultServeMux is the default ServeMux used by Serve. var DefaultServeMux = &defaultServeMux

var defaultServeMux ServeMux 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 感兴趣的看看 ServeMux 是一个 HTTP 请求多路复用器(HTTP Request multiplexer)。

具体来说,它主要有以下两个功能:

路由功能,将请求的 URL 与一组已经注册的路由模式(pattern)进行匹配,并选择一个最接近模式,调用其处理函数。 它会清理请求 URL 与 Host 请求头,清除端口号,并对包含 .. 和重复/的URL进行处理 小结:我们这块知道了最终请求是交给了ServeMux的Handle方法来处理 看看: http.HandleFunc

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

// 再看看: DefaultServeMux.HandleFunc(pattern, handler)

func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) { if handler == nil { panic("http: nil handler") } mux.Handle(pattern, HandlerFunc(handler)) }

// 原来handler 强转为 HandlerFunc 类型,而HandlerFunc类型已经实现了ServeHTTP(w ResponseWriter, r *Request)签名 type HandlerFunc func(ResponseWriter, *Request)

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

// 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) 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 小结:原来 http.HandleFunc最终调用的也是func (mux *ServeMux) Handle(pattern string, handler Handler) 看看 : http.NewServeMux

// NewServeMux allocates and returns a new ServeMux. func NewServeMux() *ServeMux { return new(ServeMux) } 1. 2. 小结: 原来我们调用的mux就是就是这个类型对象 go WEB 核心流程梳理

Request:用户请求的信息,用来解析用户的请求信息,包括post、get、cookie、url等信息

Response:服务器需要反馈给客户端的信息

Conn:用户的每次请求链接

Handler:处理请求和生成返回信息的处理逻辑

除去细节,理解HTTP构建的网络应用只要关注两个端--客户端(client)和服务端(server),两个端的交互来自client的request,以及server端的response。所谓的http服务器,主要在于如何接受client的request,并向client返回response。

接收request的过程中,最重要的莫过于路由(router),即实现一个Multiplexer器。Go中既可以使用内置的mutilplexer--DefaultServeMux,也可以自定义。Multiplexer路由的目的就是为了找到处理器函数(hander),后者将对request进行处理,同时构建response。

Go实现的流程:

Client --> Request --> Multiplexer(router) --> Handler --> Response -->Client

因此,理解go中的http服务,最重要的就是要理解Multiplexer和hander,Golang中的Multiplexer基于ServerMux结构,同时也实现了Handler接口。

hander函数:具有func(w http.ResponseWriter, r *http.Requests)签名的函数 handler处理器(函数):经过HanderFunc结构包装的handler函数,它实现了ServeHTTP接口方法的函数。调用handler处理器的ServeHTTP方法时,即调用handler函数本身。 handler对象:实现了Hander接口ServeHTTP方法的结构。