前言:
golang處理http一般有這幾種方式:
直接使用net包(這個是很底層的包,是tcp層次,需要自己進行封裝)。
使用http包(這個是已經封裝好的,可以直接使用的)。
最後的是使用第三方的開源包(不太建議,一般是使用官方的http包,方便升級和遷移)。
http包中包含http請求的用戶端和服務端處理流程的實現。這些方法以函數的方式來實現http各個流程,如:Get,Head,Post,以及PostForm。golang的http處理和其餘的web語言類似但又有不同之處,其餘的語言比如php是利用進程來處理每個請求的而golang是在底層包中就實現了用協程來hold各個http串連,這是其最大的不同,這樣golang就直接用其http包實現後端伺服器的功能而不必使用nginx或tomact等傳統伺服器來協助hold住http串連了。當然對於負載平衡等功能還是可以藉助nginx的功能的。(golang雖然是使用協程來操作網路io等,但是其底層也一樣是使用epoll等網路模型)
實現一個簡單的web伺服器:
一個簡單的http伺服器,curl 127.0.0.1:3000/foo訪問
http服務端處理函數:
func Handle(pattern string, handler Handler) 這個是根據匹配來給其分配對應的處理邏輯方法。
func HandleFunc(pattern string, handler func(ResponseWriter, *Request))同上,主要用來實現動態檔案內容的展示。
func ListenAndServe(addr string, handler Handler) error 監聽網路請求然後調用具有handler的Serve去處理串連請求.通常情況下Handler是nil,使用預設的DefaultServeMux 。
func ListenAndServeTLS(addr string, certFile string, keyFile string, handler Handler) error 該函數與ListenAndServe功能基本相同,二者不同之處是該函數需要HTTPS串連.也就是說,必須給該服務Serve提供一個包含整數的秘鑰的檔案,如果認證是由認證機構簽署的,那麼認證檔案必須是服務憑證之後跟著CA認證。
func ServeFile(w ResponseWriter, r *Request, name string)利用指定的檔案或者目錄的內容來響應相應的請求。
func SetCookie(w ResponseWriter, cookie *Cookie)給w設定cookie。
func StatusText(code int) string對於http狀態代碼返迴文本表示,如果這個code未知,則返回空的字串 。
func MaxBytesReader(w ResponseWriter, r io.ReadCloser, n int64) io.ReadCloser該函數類似於io.LimitReader但是該函數是用來限制請求體的大小.與io.LimitReader不同的是,該函數返回一個ReaderCloser,當讀超過限制時,返回一個non-EOF,並且當Close方法調用時,關閉底層的reader.該函數組織用戶端惡意發送大量請求,浪費伺服器資源。
func ParseHTTPVersion(vers string) (major, minor int, ok bool)解析http字串版本進行解析,”HTTP/1.0” 返回 (1, 0, true) 。
func ProxyURL(fixedURL *url.URL) func(*Request) (*url.URL, error)返回一個用於傳輸的代理函數,該函數總是返回相同的URL 。
func Redirect(w ResponseWriter, r *Request, urlStr string, code int)返回一個重新導向的url給指定的請求,這個重新導向url可能是一個相對請求路徑的一個相對路徑.
func Serve(l net.Listener, handler Handler) error該函數接受listener l的傳入http串連,對於每一個串連建立一個新的服務協程,這個服務協程讀取請求然後調用handler來給他們響應.handler一般為nil,這樣預設的DefaultServeMux被使用.
http用戶端請求函數:
Client具有Do,Get,Head,Post以及PostForm等方法。 其中Do方法可以對Request進行一系列的設定,而其他的對request設定較少。如果Client使用預設的Client,則其中的Get,Head,Post以及PostForm方法相當於預設的http.Get,http.Post,http.Head以及http.PostForm函數。
func (c *Client) Do(req *Request) (resp *Response, err error)Do發送http請求並且返回一個http響應,遵守client的策略,如重新導向,cookies以及auth等.錯誤經常是由於策略引起的,當err是nil時,resp總會包含一個非nil的resp.body.當調用者讀完resp.body之後應該關閉它,如果resp.body沒有關閉,則Client底層RoundTripper將無法重用存在的TCP串連去服務接下來的請求,如果resp.body非nil,則必須對其進行關閉.通常來說,經常使用Get,Post,或者PostForm來替代Do.
func (c *Client) Get(url string) (resp *Response, err error)利用get方法請求指定的url.Get請求指定的頁面資訊,並返回實體主體。
func (c *Client) Head(url string) (resp *Response, err error)利用head方法請求指定的url,Head只返回頁面的首部。
func (c *Client) Post(url string, bodyType string, body io.Reader) (resp *Response, err error)利用post方法請求指定的URl,如果body也是一個io.Closer,則在請求之後關閉它
func (c *Client) PostForm(url string, data url.Values) (resp *Response, err error)利用post方法請求指定的url,利用data的key和value作為請求體.
Do方法可以靈活的對request進行配置,然後進行請求。利用http.Client以及http.NewRequest來類比請求。類比request中帶有cookie的請求。
func (c *Cookie) String() string該函數返回cookie的序列化結果。如果只設定了Name和Value欄位,序列化結果可用於HTTP請求的Cookie頭或者HTTP回複的Set-Cookie頭;如果設定了其他欄位,序列化結果只能用於HTTP回複的Set-Cookie頭。
func (d Dir) Open(name string) (File, error)type FileFile是通過FileSystem的Open方法返回的,並且能夠被FileServer實現.該方法與*os.File行為表現一樣。
func FileServer(root FileSystem) HandlerFileServer返回一個使用FileSystem介面提供檔案訪問服務的HTTP處理器。可以使用httpDir來使用作業系統的FileSystem介面實現。其主要用來實現靜態檔案的展示。
func NotFoundHandler() Handler返回一個簡單的要求處理常式,該處理器對任何請求都會返回”404 page not found”
func RedirectHandler(url string, code int) Handler使用給定的狀態代碼將它接受到的任何請求都重新導向到給定的url
func StripPrefix(prefix string, h Handler) Handler將請求url.path中移出指定的首碼,然後將省下的請求交給handler h來處理,對於那些不是以指定首碼開始的路徑請求,該函數返回一個http 404 not found 的錯誤.
func TimeoutHandler(h Handler, dt time.Duration, msg string) Handler具有逾時限制的handler,該函數返回的新Handler調用h中的ServerHTTP來處理每次請求,但是如果一次調用超出時間限制,那麼就會返回給要求者一個503服務要求不可達的訊息,並且在ResponseWriter返回逾時錯誤.
其中FileServer經常和StripPrefix一起連用,用來實現靜態檔案展示,舉例如下:
type HandlerFuncHandlerFunc type是一個適配器,通過類型轉換我們可以將普通的函數作為HTTP處理器使用。如果f是一個具有適當簽名的函數,HandlerFunc(f)通過調用f實現了Handler介面。
typeHijackerinterface{// Hijack讓調用者接管串連,在調用Hijack()後,http server庫將不再對該串連進行處理,對於該串連的管理和關閉責任將由調用者接管.Hijack() (net.Conn, *bufio.ReadWriter, error)//conn表示連線物件,bufrw代表該串連的讀寫緩衝對象。
func NewRequest(method, urlStr string, body io.Reader) (*Request, error)利用指定的method,url以及可選的body返回一個新的請求.如果body參數實現了io.Closer介面,Request傳回值的Body 欄位會被設定為body,並會被Client類型的Do、Post和PostForm方法以及Transport.RoundTrip方法關閉。
func ReadRequest(b *bufio.Reader) (req *Request, err error)從b中讀取和解析一個請求.
func (r *Request) AddCookie(c *Cookie)給request添加cookie,AddCookie向請求中添加一個cookie.按照RFC 6265 section 5.4的規則,AddCookie不會添加超過一個Cookie頭欄位.這表示所有的cookie都寫在同一行,用分號分隔(cookie內部用逗號分隔屬性)
func (r *Request) Cookie(name string) (*Cookie, error)返回request中指定名name的cookie,如果沒有發現,返回ErrNoCookie
func (r *Request) Cookies() []*Cookie返回該請求的所有cookies
func (r *Request) SetBasicAuth(username, password string)利用提供的使用者名稱和密碼給http基本許可權提供具有一定許可權的header。當使用http基本授權時,使用者名稱和密碼是不加密的
func (r *Request) UserAgent() string如果在request中發送,該函數返回用戶端的user-Agent。
func (r *Request) FormFile(key string) (multipart.File, *multipart.FileHeader, error)對於指定格式的key,FormFile返回合格第一個檔案,如果有必要的話,該函數會調用ParseMultipartForm和ParseForm。
func (r *Request) FormValue(key string) string返回key擷取的隊列中第一個值。在查詢過程中post和put中的主題參數優先順序高於url中的value。為了訪問相同key的多個值,調用ParseForm然後直接檢查RequestForm。
func (r *Request) MultipartReader() (*multipart.Reader, error)如果這是一個有多部分組成的post請求,該函數將會返回一個MIME 多部分reader,否則的話將會返回一個nil和error。使用本函數代替ParseMultipartForm可以將請求body當做流stream來處理。
func (r *Request) ParseForm() error解析URL中的查詢字串,並將解析結果更新到r.Form欄位。對於POST或PUT請求,ParseForm還會將body當作表單解析,並將結果既更新到r.PostForm也更新到r.Form。解析結果中,POST或PUT請求主體要優先於URL查詢字串(同名變數,主體的值在查詢字串的值前面)。如果請求的主體的大小沒有被MaxBytesReader函數設定限制,其大小預設限制為開頭10MB。ParseMultipartForm會自動調用ParseForm。重複調用本方法是無意義的。
func (r *Request) ParseMultipartForm(maxMemory int64) errorParseMultipartForm將請求的主體作為multipart/form-data解析。請求的整個主體都會被解析,得到的檔案記錄最多 maxMemery位元組儲存在記憶體,其餘部分儲存在硬碟的temp檔案裡。如果必要,ParseMultipartForm會自行調用 ParseForm。重複調用本方法是無意義的。
func (r *Request) PostFormValue(key string) string返回post或者put請求body指定元素的第一個值,其中url中的參數被忽略。
func (r *Request) ProtoAtLeast(major, minor int) bool檢測在request中使用的http協議是否至少是major.minor
func (r *Request) Referer() string如果request中有refer,那麼refer返回相應的url。Referer在request中是拼錯的,這個錯誤從http初期就已經存在了。該值也可以從Headermap中利用Header[“Referer”]擷取;在使用過程中利用Referer這個方法而不是map的形式的好處是在編譯過程中可以檢查方法的錯誤,而無法檢查map中key的錯誤。
func (r *Request) Write(w io.Writer) errorWrite方法以有線格式將HTTP/1.1請求寫入w(用於將請求寫入下層TCPConn等)。本方法會考慮請求的如下欄位:Host URL Method (defaults to “GET”) Header ContentLength TransferEncoding Body如果存在Body,ContentLength欄位<= 0且TransferEncoding欄位未顯式設定為[“identity”],Write方法會顯式添加”Transfer-Encoding: chunked”到請求的頭域。Body欄位會在發送完請求後關閉。
func (r *Request) WriteProxy(w io.Writer) error該函數與Write方法類似,但是該方法寫的request是按照http代理的格式去寫。尤其是,按照RFC 2616 Section 5.1.2,WriteProxy會使用絕對URI(包括協議和主機名稱)來初始化請求的第1行(Request-URI行)。無論何種情況,WriteProxy都會使用r.Host或r.URL.Host設定Host頭。
type Response指對於一個http請求的響應response
func Get(url string) (resp *Response, err error)利用GET方法對一個指定的URL進行請求,如果response是如下重新導向中的一個代碼,則Get之後將會調用重新導向內容,最多10次重新導向。
301 (永久重新導向,告訴用戶端以後應該從新地址訪問) 。
302 (暫時性重新導向,作為HTTP1.0的標準,以前叫做Moved Temporarily,現在叫做Found。現在使用只是為了相容性處理,包括PHP的預設Location重新導向用到也是302),註:303和307其實是對302的細化。
303 (對於Post請求,它表示請求已經被處理,用戶端可以接著使用GET方法去請求Location裡的URl) 。
307 (臨時重新導向,對於Post請求,表示請求還沒有被處理,用戶端應該向Location裡的URL重新發起Post請求) 。如果有太多次重新導向或者有一個http協議錯誤將會導致錯誤。當err為nil時,resp總是包含一個非nil的resp.body,Get是對DefaultClient.Get的一個封裝。
func Head(url string) (resp *Response, err error)該函數功能見net中Head方法功能。該方法與預設的defaultClient中Head方法一致。
func Post(url string, bodyType string, body io.Reader) (resp *Response, err error)該方法與預設的defaultClient中Post方法一致。
func PostForm(url string, data url.Values) (resp *Response, err error)該方法與預設的defaultClient中PostForm方法一致。
協程ID擷取:
前期的golang版本 官方是提供函數擷取協程號的,後來防止協程被濫用,將方法屏蔽了,但是確提供了一種新的方式---就是通過堆棧的方式擷取,只是這種方式不能用在生產環境避免影響效能(這種設計思路可以借鑒下)
調用這個方法就可以擷取了。