Go Web學習 -標準庫 net/http 使用

Luson發表於2022-02-17

實現一個簡單的 http 服務

package main

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

func main() {
    http.HandleFunc("/", func(rw http.ResponseWriter, r *http.Request) {
        fmt.Fprint(rw, "hello word")
    })
    log.Fatal(http.ListenAndServe(":9777", nil))
}

原理解析:
在main()函式的第一行,我們通過http.HandleFunc定義了路由為”/“的響應函式,這個響應函式,接受傳來的Request,並對Response做一定的處理即寫入HelloWorld然後直接返回給瀏覽器。然後便可以直接呼叫http.ListenAndServe來監聽本地的9777埠,便可以直接在瀏覽器上看到Hello World。

HandleFunc 的實現

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

DefaultServeMux是http包中的全域性變數,它的原型是ServeMux這個結構體。

type ServeMux struct {
    mu    sync.RWMutex        //保護m
    m     map[string]muxEntry //URL:Handler對映表
    hosts bool
}
type muxEntry struct {
    explicit bool
    h        Handler
    pattern  string
}

ServerMux 這個結構體的 HandelFunc 方法:

// HandleFunc registers the handler function for the given pattern.
func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
    mux.Handle(pattern, HandlerFunc(handler))  //又呼叫了mux.Handle
}

而 mux.Handle 就比較簡單了,就是將 func(http.ResponseWriter,*http.Request)轉換為 http.Handler 然後放入mux的map中。而http.Handler是一個介面型別,二者是如何轉換的?不妨看看 mux.HandleFunc

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

上面這個函式,其實就是一個實現了 http.Handler 介面的型別,該型別底層基礎型別就是 func(ResponseWriter, *Request),我們知道在go語言中除了 指標與介面 其他基礎型別也是可以定義方法的,標準庫定義這個一個型別,為的就是將 普通func(ResponseWriter, *Request) 適配到 http.Handler介面

ListenAndServe這個方法

// ListenAndServe always returns a non-nil error.
func ListenAndServe(addr string, handler Handler) error {
    server := &Server{Addr: addr, Handler: handler}
    return server.ListenAndServe()
}

原始碼中可以看到該方法會將傳入進來的addr引數和handler送給Server這個結構體,從而新建一個server然後呼叫這個server的ListenAndServe方法,處理流程大致如下:
server監聽到有新連結進來,建立一個goroutine來處理新連結
在goroutine中,將請求和響應分別封裝為 http.Request和http.ResponseWriter物件。然後用這兩個物件作為函式引數呼叫 server.Handler.serveHTTP(…), 而server.Handler 即為我們傳入的 http.ServeMux 物件,而http.ServeMux物件的serveHTTP方法,我們都沒有碰過,裡面到底做了什麼?

http.ServeMux物件的serveHTTP方法做的事,其實就是根據 http.Request物件中的URL 在自己的map中查詢對應的Handler(這個又是我們在step1中新增的),然後執行。

繞了一大圈,簡單來說就是 每當有新請求進來,server都會為我們新建一個goroutine,並在其中根據請求URL呼叫 我們在建立server之前新增的 URL:Handler對映表(通過server中的http.Handler欄位混入)中的相應URL的Handler.

net/http包中幾個重要的型別:
http.ServeMux: 建立URL:Handler對映表
http.Server: 執行HTTP Server
http.Request: 封裝客戶端HTTP請求資料
http.ResponseWriter: 用來構造伺服器端HTTP響應資料
http.Handler: URL處理程式必須實現的介面

本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章