1. 程式人生 > >Go語言中處理 HTTP 伺服器

Go語言中處理 HTTP 伺服器

文章目錄

1 概述

net/http 提供了HTTP伺服器端和客戶端的實現。本文說明關於伺服器端的部分。

快速開始:

package main

import (
  "log"
  "net/http"
)

func main() {
  // 設定 路由
  http.HandleFunc("/", IndexAction)

  // 開啟監聽
  log.Fatal(http.
ListenAndServe(":8888", nil)) } func IndexAction(w http.ResponseWriter, r *http.Request) { w.Write([]byte(`<h1 align="center">來自小韓說課的問候</h1>`)) }

執行程式,在瀏覽器上請求: localhost:8888,你會看到我們的結果:

第一個伺服器程式

Go語言構建HTTP伺服器還是很容易的。深入說明。

2 http.Server 型別

HTTP 伺服器在 Go 語言中是由 http.Server 結構體物件實現的。參考 http.ListenAndServe()

的實現:

// 檔案:src/net/http/server.go

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

可見過程是先例項化 Server 物件,再完成 ListenAndServe 。其中 Serve 物件就是表示 HTTP 伺服器的物件。其結構如下

// 檔案:src/net/http/server.go

type Server struct {
  Addr    string  // TCP 監聽地址, 留空為:":http"
  Handler Handler // 呼叫的 handler(路由處理器), 設為 nil 表示 http.DefaultServeMux

  TLSConfig *tls.Config // TLS 配置物件
  ReadTimeout time.Duration // 請求超時時長
  ReadHeaderTimeout time.Duration // 請求頭超時時長
  WriteTimeout time.Duration // 響應超時時長
  IdleTimeout time.Duration // 請求空閒時長(keep-alive下兩個請求間)
  MaxHeaderBytes int // 請求頭的最大長度
  TLSNextProto map[string]func(*Server, *tls.Conn, Handler) // NPN 型協議升級出現時接管TLS連線的處理器函式對映表
  ConnState func(net.Conn, ConnState) // 狀態轉換事件處理器
  ErrorLog *log.Logger // 日誌記錄物件
  disableKeepAlives int32     // accessed atomically.
  inShutdown        int32     // accessed atomically (non-zero means we're in Shutdown)
  nextProtoOnce     sync.Once // guards setupHTTP2_* init
  nextProtoErr      error     // result of http2.ConfigureServer if used
  mu         sync.Mutex
  listeners  map[*net.Listener]struct{}
  activeConn map[*conn]struct{}
  doneChan   chan struct{}
  onShutdown []func()
}

可見 Server 定義了伺服器需要的資訊。

例項化了 Server 物件後,呼叫其 (srv *Server) ListenAndServe() error 方法。該方法會監聽 srv.Addr 指定的 TCP 地址,並通過 (srv *Server) Serve(l net.Listener) error 方法接收瀏覽器端連線請求。Serve 方法會接收監聽器 l 收到的每一個連線,併為每一個連線建立一個新的服務程序。

該 go 程序會讀取請求,然後呼叫 srv.Handler 處理並響應。srv.Handler 通常會是 nil,這意味著需要呼叫 http.DefaultServeMux 來處理請求,這個 DefaultServeMux 是預設的路由,我們使用 http.HandleFunc 就是在 http.DefaultServeMux 上註冊方法。

3 http.DefaultServeMux 預設路由物件

看 Go 的原始碼,瞭解 http.HandleFunc():

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

可以看出來,註冊的函式被 DefaultServerMux 來使用了。註冊的時候,需要 pattern,就是 URL 模式,以及處理該 URL 模式的函式。

DefaultServerMuxhttp.ServeMux 型別的一個預設例項,ServeMux 就是路由。其主要結構是一個對映 map,用來儲存 URL 模式和相關處理函式的關係。參看原始碼可以看出來:

type ServeMux struct {
  mu    sync.RWMutex
  m     map[string]muxEntry // 對映表
  hosts bool // whether any patterns contain hostnames
}
type muxEntry struct {
  h       Handler
  pattern string
}

可以呼叫多次 http.HandleFunc() 來註冊多個處理器。

URL 模式是固定的、由根開始的路徑。處理器的 URL 模式匹配原則是 左側長度優先匹配
例如有模式 /path/article//path/ ,如果請求的 URL 是 /path/other/ 會由 /path/ 註冊的處理器來處理,而 URL 為 /path/article/42/ 會由 /path/article/ 來處理。

以斜槓結尾的模式代表一個由根開始的子樹,就是以當前為字首的都會匹配。因此 / 會匹配所有的未被其他註冊的模式匹配的路徑。

4 處理器

處理器可以由函式或實現 Handler 介面的物件來充當。Handler 介面就是要求物件實現和處理器函式一致的方法。看 http.Handler 介面的實現原始碼:

type Handler interface {
  ServeHTTP(ResponseWriter, *Request)
}

我們使用函式 http.HandleFunc 註冊處理函式,而使用 http.Handle 函式來註冊滿足 Handler 介面的處理物件。效果是一致的。

完!
原文出自:小韓說課
微信關注:小韓說課
小韓說課