在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伺服器響應並結束連線,整個過程如下圖所示:
請求與響應
一個完整http事務,由一個客戶端的請求和Web伺服器響應構成,客戶端發起的請求,包括三個部分:請求行
、請求頭
和請求體
,而Web伺服器的響應同樣包含三部分:響應行
、響應頭
和響應體
,如下圖所示:。
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.HandlerFunc
,http.HandlerFunc
也實現http.Handler
,http.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.DefaultServeMux
,DefaultServeMux
的定義如下程式碼所示:
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開發,還是有很多東西要學的。