這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
構建一個HTTP伺服器的簡單例子
package mainimport ("net/http")func SayHello(w http.ResponseWriter, req *http.Request) {w.Write([]byte("Hello"))}func main() {http.HandleFunc("/hello", SayHello)http.ListenAndServe(":8001", nil)}
當我們訪問 地址IP:8001/hello 就會得到“hello”輸出在瀏覽器上。
我們分析下這是怎麼實現的。先看下介面函數ListenAndServe
func ListenAndServe(addr string, handler Handler) error {server := &Server{Addr: addr, Handler: handler}return server.ListenAndServe()}
實際上是產生一個Server對象,然後執行Server對象的函數ListenAndServe()。在分析ListenAndServe()之前我們先看下Handler,實際上Handler是個介面
type Handler interface {ServeHTTP(ResponseWriter, *Request)}
在看Request和ResponseWriter
描述要求標頭的Request
type Request struct {Method stringURL *url.URLProto string // "HTTP/1.0"ProtoMajor int // 1ProtoMinor int // 0Header HeaderBody io.ReadCloserContentLength int64TransferEncoding []stringClose boolHost stringForm url.ValuesPostForm url.ValuesMultipartForm *multipart.FormTrailer HeaderRemoteAddr stringRequestURI stringTLS *tls.ConnectionStateCancel <-chan struct{}}
描述應答的ResponseWriter
type ResponseWriter interface {// Header returns the header map that will be sent by// WriteHeader. Changing the header after a call to// WriteHeader (or Write) has no effect unless the modified// headers were declared as trailers by setting the// "Trailer" header before the call to WriteHeader (see example).// To suppress implicit response headers, set their value to nil.Header() Header// Write writes the data to the connection as part of an HTTP reply.// If WriteHeader has not yet been called, Write calls WriteHeader(http.StatusOK)// before writing the data. If the Header does not contain a// Content-Type line, Write adds a Content-Type set to the result of passing// the initial 512 bytes of written data to DetectContentType.Write([]byte) (int, error)// WriteHeader sends an HTTP response header with status code.// If WriteHeader is not called explicitly, the first call to Write// will trigger an implicit WriteHeader(http.StatusOK).// Thus explicit calls to WriteHeader are mainly used to// send error codes.WriteHeader(int)}
現在我們回到Server類的ListenAndServe()函數
func (srv *Server) ListenAndServe() error {addr := srv.Addrif addr == "" {addr = ":http"}ln, err := net.Listen("tcp", addr)if err != nil {return err}return srv.Serve(tcpKeepAliveListener{ln.(*net.TCPListener)})}
實際上這個函數只是執行TCP地址監聽,然後執行Server函數,我們看下該函數幹了什;函數頭有解釋,大概意思就是監聽一個地址,然後接受串連,然後產生一個goroutine讀取這個新的串連請求,而是調用handler去處理這個請求
// Serve accepts incoming connections on the Listener l, creating a// new service goroutine for each. The service goroutines read requests and// then call srv.Handler to reply to them.// Serve always returns a non-nil error.func (srv *Server) Serve(l net.Listener) error {defer l.Close()if fn := testHookServerServe; fn != nil {fn(srv, l)}var tempDelay time.Duration // how long to sleep on accept failureif err := srv.setupHTTP2(); err != nil {return err}for {rw, e := l.Accept()if e != nil {if ne, ok := e.(net.Error); ok && ne.Temporary() {if tempDelay == 0 {tempDelay = 5 * time.Millisecond} else {tempDelay *= 2}if max := 1 * time.Second; tempDelay > max {tempDelay = max}srv.logf("http: Accept error: %v; retrying in %v", e, tempDelay)time.Sleep(tempDelay)continue}return e}tempDelay = 0c := srv.newConn(rw)c.setState(c.rwc, StateNew) // before Serve can returngo c.serve()}}
handler是啥?我們一開始就說明了,實際上它是一個介面,具體怎麼實現由客戶定義。但是我們的例子中沒有傳入這樣一個handler。那這個handler怎麼來呢?我們繼續分析,接受用戶端串連後,執行
c := srv.newConn(rw)c.setState(c.rwc, StateNew) // before Serve can returngo c.serve()
產生一個連線物件,然後執行連線物件的函數server,我們接著分析該函數:
// Serve a new connection.func (c *conn) serve() {c.remoteAddr = c.rwc.RemoteAddr().String()defer func() {if err := recover(); err != nil {const size = 64 << 10buf := make([]byte, size)buf = buf[:runtime.Stack(buf, false)]c.server.logf("http: panic serving %v: %v\n%s", c.remoteAddr, err, buf)}if !c.hijacked() {c.close()c.setState(c.rwc, StateClosed)}}()if tlsConn, ok := c.rwc.(*tls.Conn); ok {if d := c.server.ReadTimeout; d != 0 {c.rwc.SetReadDeadline(time.Now().Add(d))}if d := c.server.WriteTimeout; d != 0 {c.rwc.SetWriteDeadline(time.Now().Add(d))}if err := tlsConn.Handshake(); err != nil {c.server.logf("http: TLS handshake error from %s: %v", c.rwc.RemoteAddr(), err)return}c.tlsState = new(tls.ConnectionState)*c.tlsState = tlsConn.ConnectionState()if proto := c.tlsState.NegotiatedProtocol; validNPN(proto) {if fn := c.server.TLSNextProto[proto]; fn != nil {h := initNPNRequest{tlsConn, serverHandler{c.server}}fn(c.server, tlsConn, h)}return}}c.r = &connReader{r: c.rwc}c.bufr = newBufioReader(c.r)c.bufw = newBufioWriterSize(checkConnErrorWriter{c}, 4<<10)for {w, err := c.readRequest()if c.r.remain != c.server.initialReadLimitSize() {// If we read any bytes off the wire, we're active.c.setState(c.rwc, StateActive)}if err != nil {if err == errTooLarge {// Their HTTP client may or may not be// able to read this if we're// responding to them and hanging up// while they're still writing their// request. Undefined behavior.io.WriteString(c.rwc, "HTTP/1.1 431 Request Header Fields Too Large\r\nContent-Type: text/plain\r\nConnection: close\r\n\r\n431 Request Header Fields Too Large")c.closeWriteAndWait()return}if err == io.EOF {return // don't reply}if neterr, ok := err.(net.Error); ok && neterr.Timeout() {return // don't reply}var publicErr stringif v, ok := err.(badRequestError); ok {publicErr = ": " + string(v)}io.WriteString(c.rwc, "HTTP/1.1 400 Bad Request\r\nContent-Type: text/plain\r\nConnection: close\r\n\r\n400 Bad Request"+publicErr)return}// Expect 100 Continue supportreq := w.reqif req.expectsContinue() {if req.ProtoAtLeast(1, 1) && req.ContentLength != 0 {// Wrap the Body reader with one that replies on the connectionreq.Body = &expectContinueReader{readCloser: req.Body, resp: w}}} else if req.Header.get("Expect") != "" {w.sendExpectationFailed()return}// HTTP cannot have multiple simultaneous active requests.[*]// Until the server replies to this request, it can't read another,// so we might as well run the handler in this goroutine.// [*] Not strictly true: HTTP pipelining. We could let them all process// in parallel even if their responses need to be serialized.serverHandler{c.server}.ServeHTTP(w, w.req)if c.hijacked() {return}w.finishRequest()if !w.shouldReuseConnection() {if w.requestBodyLimitHit || w.closedRequestBodyEarly() {c.closeWriteAndWait()}return}c.setState(c.rwc, StateIdle)}}
該函數開始嘗試TLS握手,如果失敗,逾時則不是TLS串連,則直接讀取http請求:
w, err := c.readRequest()
接著產生一個服務物件,執行服務物件的服務函數:
serverHandler{c.server}.ServeHTTP(w, w.req)
我們看下該函數:
func (sh serverHandler) ServeHTTP(rw ResponseWriter, req *Request) {handler := sh.srv.Handlerif handler == nil {handler = DefaultServeMux}if req.RequestURI == "*" && req.Method == "OPTIONS" {handler = globalOptionsHandler{}}handler.ServeHTTP(rw, req)}
意思很明顯,如果handler為空白,則賦值一個DefaultServeMux,也就是預設的Handler,然後執行該預設Handler的服務函數來處理請求:
handler.ServeHTTP(rw, req)
下篇我們將分析該預設Handler.