Go Web開發入坑指南

張君鴻發表於2019-03-26

在Go語言中開發Web應用,真的是一件非常簡單的事情,因為Go語言標準庫中就有非常成熟且簡單的Web開發包:net/http

net/http封裝了開發Web應用所需要的大部分功能,因此,在Go語言中使用net/http開發Web應用程式時,我們甚至都不用像其他語言(比如PHP)一樣需要自己再搭一個Apache或nginx等Web伺服器,而是隻需要簡單幾行程式碼就可以搭建一個Web服務應用。

Web基礎

當然,雖然使用Go的net/http包可以簡單開發Web應用,但我們在開發中仍然需要牢固地掌握開發Web程式所需要的基礎知識,而Web開發中最基礎和最核心的知識就是:HTTP協議

http協議是Web伺服器與客戶端(最常見就是瀏覽器)之間通訊的語言與規範,瀏覽器向Web發起請求到Web伺服器響應並結束連線,整個過程如下圖所示:

Go Web開發入坑指南

圖片摘自《HTTP權威指南》

請求與響應

一個完整http事務,由一個客戶端的請求和Web伺服器響應構成,客戶端發起的請求,包括三個部分:請求行請求頭請求體,而Web伺服器的響應同樣包含三部分:響應行響應頭響應體,如下圖所示:。

Go Web開發入坑指南

圖片摘自《HTTP權威指南》

http協議的相關知識遠不只這些,我們有空再談談。

Go建立Web伺服器的幾種方式

http.HandleFunc函式

使用HandleFunc函式是http封裝好的一個函式,可以直接使用,第一個引數是web請求路徑,第二個引數是的func(writer http.ResponseWriter, request *http.Request)函式。

再使用http.ListenAndServe(":8080",nil)語句,監聽8080埠,執行程式後。

使用http://localhost:8080,便會輸出一起學習Go Web程式設計吧

其中http.ResponseWriter代表對客戶端的響應體,而http.Request代表客戶端傳送伺服器的請求資料。

func hello(writer http.ResponseWriter, request *http.Request) {
    writer.Write([]byte("一起學習Go Web程式設計吧"));
}

func main(){
    http.HandleFunc("/hello",hello)
    log.Fatal(http.ListenAndServe(":8080",nil))
}

複製程式碼

http.Handle函式

HandleFunc一樣,Handle也是http封裝好的函式,第一個引數跟HandleFunc一樣,而第二個引數則是必須是實現了http.Handler介面的型別,http.Handler在http包的定義如下:

type Handler interface {
	ServeHTTP(ResponseWriter, *Request)
}
複製程式碼

下面我們定義一個Controller結構體,在該結構定義ServeHTTP方法,因此Controller結構也實現http.Handler介面,而通過http.HandlerFunc也能將hello方法轉成一個實現http.HandlerFunchttp.HandlerFunc也實現http.Handlerhttp.HandlerFunc在http包的定義如下:

type HandlerFunc func(ResponseWriter, *Request)

// ServeHTTP calls f(w, r).
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
	f(w, r)
}
複製程式碼

其實,在上面的例子中,我們將hello傳給http.HandleFunc函式時,HandleFunc函式也是使用http.HandlerFunc將hello轉換成http.HandlerFunc的。

下面有關http.Handle的示例:

type Controller struct {}
func (c Controller)ServeHTTP(writer http.ResponseWriter, request *http.Request){
    writer.Write([]byte("hello,1"));
}

func hello(writer http.ResponseWriter, request *http.Request) {
    writer.Write([]byte("hello,2"));
}

func main(){
    http.Handle("/hello1",&Controller{})
    http.Handle("/hello2",http.HandlerFunc(hello))
    log.Fatal(http.ListenAndServe(":8080",nil))
}
複製程式碼

執行程式後,在瀏覽器輸入下面的地址:

http://localhost:8080/hell1, 輸出:hello,1

http://localhost:8080/hell2, 輸出:hello,2

http.ServeMux

無論是使用http.Handle還是http.HandleFunc函式,其實底層程式碼都是使用http.DefaultServeMuxDefaultServeMux的定義如下程式碼所示:

var DefaultServeMux = &defaultServeMux

var defaultServeMux ServeMux
複製程式碼
type Controller struct {}
func (c Controller)ServeHTTP(writer http.ResponseWriter, request *http.Request){
    writer.Write([]byte("hello,1"));
}

func hello(writer http.ResponseWriter, request *http.Request) {
    writer.Write([]byte("hello,2"));
}

func main(){
    mux := &http.ServeMux{}
    mux.HandleFunc("/hello1",hello)
    mux.Handle("/hello2",http.HandlerFunc(hello))
    mux.Handle("/hello3",&Controller{})

    log.Fatal(http.ListenAndServe(":8080",mux))
}
複製程式碼

執行程式後,在瀏覽器輸入下面的地址:

http://localhost:8080/hell1, 輸出:hello,1

http://localhost:8080/hell2, 輸出:hello,1

http://localhost:8080/hell3, 輸出:hello,2

http.Server

http.Server是http包中對web更加底層的支援,我們前面使用的方法,都是對http.Server的封裝而已,如果直接使用http.Server,則可以自定義更多的引數,如果連線超時等引數,因此我們下面直接使用http.Server開發Web服務。

func main() {
    myHandler := &http.ServeMux{}
    myHandler.HandleFunc("/hello", func(w http.ResponseWriter, r *http.Request) {
        w.Write([]byte("hello"))
    })
    s := &http.Server{
        Addr:           ":8080",
        Handler:        myHandler,
        ReadTimeout:    10 * time.Second,
        WriteTimeout:   10 * time.Second,
        MaxHeaderBytes: 1 << 20,
    }
    log.Fatal(s.ListenAndServe())
}

複製程式碼

執行程式後,在瀏覽器輸入下面的地址:

http://localhost:8080/hello, 輸出:hello

總結

通過上面的例子,可以看出Go Web開發可很簡單,但是實際中,一個真正Web應用所要做的事,遠不只這麼簡單,對於Go Web開發,還是有很多東西要學的。

相關文章