Golang中http包的具體使用
Go語(yǔ)言內(nèi)置的net/http包十分優(yōu)秀,提供了http客戶端和服務(wù)器的實(shí)現(xiàn)。
超文本傳輸協(xié)議(HTTP,HyperText Transfer Protocol)是互聯(lián)網(wǎng)上應(yīng)用最為廣泛的一種網(wǎng)絡(luò)傳輸協(xié)議,所有的www文件都必須遵循這個(gè)標(biāo)準(zhǔn)。設(shè)計(jì)HTTP最初的目的是為了提供一種發(fā)布和接收HTML頁(yè)面的方法。
一. HTTP客戶端
基本的HTTP/HTTPS請(qǐng)求Get,Head,Post和PostForm函數(shù)發(fā)出HTTP/HTTPS請(qǐng)求。
resp, err := http.Get("http://example.com") //... resp, err = http.Post("http://example.com", "image/jpeg", &buf) //... resp, err = http.PostForm("http://example.com", url.Values{"key": {"value"}, "id": {"123"}})
程序在使用完response后必須關(guān)閉回復(fù)的主體。
package main import ( "io/ioutil" "log" "net/http" ) func main() { resp, err := http.Get("http://example.com") if err != nil { log.Println("http get fail") return } //關(guān)閉回復(fù)主體 defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) //... }
1.1 Get請(qǐng)求
函數(shù)簽名:
func Get(url string) (resp *Response, err error)
Get向指定的URL發(fā)出Get請(qǐng)求,如果回應(yīng)的狀態(tài)碼如下,Get會(huì)調(diào)用c.CheckRedirect后執(zhí)行重定向。
- 301(Moved Permanently)
- 302(Found)
- 303(See Other)
- 307(Temporary Redirect)
如果c.CheckRedirect執(zhí)行失敗或存在HTTP協(xié)議錯(cuò)誤時(shí),本方法返回錯(cuò)誤。如果回應(yīng)的狀態(tài)碼不是2xx,本方法并不會(huì)返回錯(cuò)誤。如果返回值err為nil,resp.Body總是非nil的,調(diào)用者應(yīng)該在讀取完resp.Body后關(guān)閉它。
Get是對(duì)DefaultClient的Get方法的包裝。
1.2 post和get示例服務(wù)端代碼
package main import ( "fmt" "io/ioutil" "net/http" ) func getHandleFunc(w http.ResponseWriter, r *http.Request) { defer r.Body.Close() data := r.URL.Query() //獲得get方法的參數(shù) fmt.Println(data.Get("name")) fmt.Println(data.Get("age")) answer := `{"status":"ok"}` w.Write([]byte(answer)) } func postHandleFunc(w http.ResponseWriter, r *http.Request) { defer r.Body.Close() //請(qǐng)求數(shù)據(jù)類(lèi)型是application/json b, err := ioutil.ReadAll(r.Body) if err != nil { fmt.Println("read request body fail ", err) return } fmt.Println(string(b)) answer := `{"statue":"ok"}` w.Write([]byte(answer)) } func handleFunc(w http.ResponseWriter, r *http.Request) { fmt.Println("get a link....") switch r.Method { case http.MethodGet: http.HandleFunc("/get", getHandleFunc) case http.MethodPost: http.HandleFunc("/post", postHandleFunc) } } func main() { http.HandleFunc("/", handleFunc) err := http.ListenAndServe(":9090", nil) if err != nil { fmt.Println("http server fail ", err) return } }
1.3 get方法示例
不帶參數(shù)客戶端
package main import ( "fmt" "io/ioutil" "log" "net/http" ) func main() { resp, err := http.Get("https://www.baidu.com") if err != nil { log.Println("http get fail ", err) return } //關(guān)閉回復(fù)主體 defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { log.Println("read resp body fail ", err) return } fmt.Print(string(body)) }
帶參數(shù)客戶端
關(guān)于Get請(qǐng)求帶參數(shù)需要使用Go語(yǔ)言內(nèi)置的net/url標(biāo)準(zhǔn)庫(kù)來(lái)處理。
package main import ( "fmt" "io/ioutil" "net/http" "net/url" ) func main() { apiUrl := "http://127.0.0.1:9090/get" //URL參數(shù) data := url.Values{} data.Set("name", "張三") data.Set("age", "20") //URL參數(shù)需要編碼,因?yàn)橛械奶厥庾址毁x予了特殊含義 u, err := url.ParseRequestURI(apiUrl) if err != nil { fmt.Println("url parse fail ", err) } u.RawQuery = data.Encode() //url encode fmt.Println(u.String()) resp, err := http.Get(u.String()) if err != nil { fmt.Printf("url %v get fail %v", u.String(), err) return } defer resp.Body.Close() b, err := ioutil.ReadAll(resp.Body) if err != nil { fmt.Println("read body fail ", err) return } fmt.Println(string(b)) }
1.4 post請(qǐng)求
函數(shù)簽名:
func Post(url string, bodyType string, body io.Reader) (resp *Response, err error)
Post向指定的URL發(fā)送一個(gè)POST請(qǐng)求。bodyType為POST的數(shù)據(jù)類(lèi)型,Body為POST數(shù)據(jù),作為請(qǐng)求的主體。如果參數(shù)body實(shí)現(xiàn)了io.Closer接口,它會(huì)在發(fā)送請(qǐng)求后被關(guān)閉。調(diào)用者有責(zé)任在讀取完返回值resp的主體后關(guān)閉它。
Post是對(duì)包變量DefaultClient的Post方法的包裝。
1.5 post示例
package main import ( "fmt" "io/ioutil" "net/http" "strings" ) func main() { apiUrl := "http://127.0.0.1:9090/post" //表單數(shù)據(jù) contenttype := "application/json" data := `{"name":"張三", "age":18}` resp, err := http.Post(apiUrl, contenttype, strings.NewReader(data)) if err != nil { fmt.Printf("url : %v post fail err : %v\n", apiUrl, err) return } defer resp.Body.Close() b, err := ioutil.ReadAll(resp.Body) if err != nil { fmt.Println("read body err ", err) return } fmt.Println(string(b)) }
1.6 自定義Client
要管理HTTP客戶端頭域,重定向和其它策略,創(chuàng)建一個(gè)client:
type Client struct { // Transport指定執(zhí)行獨(dú)立、單次HTTP請(qǐng)求的機(jī)制。 // 如果Transport為nil,則使用DefaultTransport。 Transport RoundTripper // CheckRedirect指定處理重定向的策略。 // 如果CheckRedirect不為nil,客戶端會(huì)在執(zhí)行重定向之前調(diào)用本函數(shù)字段。 // 參數(shù)req和via是將要執(zhí)行的請(qǐng)求和已經(jīng)執(zhí)行的請(qǐng)求(切片,越新的請(qǐng)求越靠后)。 // 如果CheckRedirect返回一個(gè)錯(cuò)誤,本類(lèi)型的Get方法不會(huì)發(fā)送請(qǐng)求req, // 而是返回之前得到的最后一個(gè)回復(fù)和該錯(cuò)誤。(包裝進(jìn)url.Error類(lèi)型里) // // 如果CheckRedirect為nil,會(huì)采用默認(rèn)策略:連續(xù)10此請(qǐng)求后停止。 CheckRedirect func(req *Request, via []*Request) error // Jar指定cookie管理器。 // 如果Jar為nil,請(qǐng)求中不會(huì)發(fā)送cookie,回復(fù)中的cookie會(huì)被忽略。 Jar CookieJar // Timeout指定本類(lèi)型的值執(zhí)行請(qǐng)求的時(shí)間限制。 // 該超時(shí)限制包括連接時(shí)間、重定向和讀取回復(fù)主體的時(shí)間。 // 計(jì)時(shí)器會(huì)在Head、Get、Post或Do方法返回后繼續(xù)運(yùn)作并在超時(shí)后中斷回復(fù)主體的讀取。 // // Timeout為零值表示不設(shè)置超時(shí)。 // // Client實(shí)例的Transport字段必須支持CancelRequest方法, // 否則Client會(huì)在試圖用Head、Get、Post或Do方法執(zhí)行請(qǐng)求時(shí)返回錯(cuò)誤。 // 本類(lèi)型的Transport字段默認(rèn)值(DefaultTransport)支持CancelRequest方法。 Timeout time.Duration }
Client類(lèi)型代表HTTP客戶端。它的零值(DefaultClient)是一個(gè)可用的使用DefaultTransport的客戶端。
Client的Transport字段一般會(huì)含有內(nèi)部狀態(tài)(緩存TCP連接),因此Client類(lèi)型值應(yīng)盡量被重用而不是每次需要都創(chuàng)建新的。Client類(lèi)型值可以安全的被多個(gè)go程同時(shí)使用。
Client類(lèi)型的層次比RoundTripper接口(如Transport)高,還會(huì)管理HTTP的cookie和重定向等細(xì)節(jié)。
//設(shè)置重定向 client := &http.Client{ CheckRedirect : redirectPolicyFunc, } resp, err := client.Get("http://example.com") //... //加請(qǐng)求頭部 req, err := http.NewRequest("Get", "http://example.com", nil) //... req.Header.Add("If-None-Match", `W/"wyzzy"`) resp, err := client.Do(req) //...
1.7 自定義Transport
go語(yǔ)言中的http.transport是一個(gè)高性能的http客戶端庫(kù),它提供了連接池、重試、超時(shí)控制等功能,可以方便地進(jìn)行 http 請(qǐng)求。
要管理代理,TLS配置,keep-alive,壓縮和其它設(shè)置,可以創(chuàng)建一個(gè)Transport,對(duì)應(yīng)Client的Transport字段。
type Transport struct { // Proxy指定一個(gè)對(duì)給定請(qǐng)求返回代理的函數(shù)。 // 如果該函數(shù)返回了非nil的錯(cuò)誤值,請(qǐng)求的執(zhí)行就會(huì)中斷并返回該錯(cuò)誤。 // 如果Proxy為nil或返回nil的*URL置,將不使用代理。 Proxy func(*Request) (*url.URL, error) // Dial指定創(chuàng)建TCP連接的撥號(hào)函數(shù)。如果Dial為nil,會(huì)使用net.Dial。 Dial func(network, addr string) (net.Conn, error) // TLSClientConfig指定用于tls.Client的TLS配置信息。 // 如果該字段為nil,會(huì)使用默認(rèn)的配置信息。 TLSClientConfig *tls.Config // TLSHandshakeTimeout指定等待TLS握手完成的最長(zhǎng)時(shí)間。零值表示不設(shè)置超時(shí)。 TLSHandshakeTimeout time.Duration // 如果DisableKeepAlives為真,會(huì)禁止不同HTTP請(qǐng)求之間TCP連接的重用。 DisableKeepAlives bool // 如果DisableCompression為真,會(huì)禁止Transport在請(qǐng)求中沒(méi)有Accept-Encoding頭時(shí), // 主動(dòng)添加"Accept-Encoding: gzip"頭,以獲取壓縮數(shù)據(jù)。 // 如果Transport自己請(qǐng)求gzip并得到了壓縮后的回復(fù),它會(huì)主動(dòng)解壓縮回復(fù)的主體。 // 但如果用戶顯式的請(qǐng)求gzip壓縮數(shù)據(jù),Transport是不會(huì)主動(dòng)解壓縮的。 DisableCompression bool // 如果MaxIdleConnsPerHost!=0,會(huì)控制每個(gè)主機(jī)下的最大閑置連接。 // 如果MaxIdleConnsPerHost==0,會(huì)使用DefaultMaxIdleConnsPerHost。 MaxIdleConnsPerHost int // ResponseHeaderTimeout指定在發(fā)送完請(qǐng)求(包括其可能的主體)之后, // 等待接收服務(wù)端的回復(fù)的頭域的最大時(shí)間。零值表示不設(shè)置超時(shí)。 // 該時(shí)間不包括獲取回復(fù)主體的時(shí)間。 ResponseHeaderTimeout time.Duration // 內(nèi)含隱藏或非導(dǎo)出字段 }
tr := &http.Transport{ TLSClientConfig: &tls.Config{ RootCAs: pool, }, DisableCompression: true, } client := &http.Client{ Transport: tr, } resp, err := client.Get("http://example.com") //...
二. 服務(wù)端
2.1 默認(rèn)server
ListenAndServer使用指定的監(jiān)聽(tīng)地址和處理器啟動(dòng)一個(gè)HTTP服務(wù)端。處理器參數(shù)通常是nil,這表示采用包變量DefaultServeMux作為處理器。
Handle和HandleFunc函數(shù)可以向DefaultServeMux添加處理器。
http.Handle("/foo", fooHandler) http.HandleFunc("/hello", func(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "hello %q", html.EscapeString(r.URL.Path)) }) log.Fatal(http.ListenAndServe(":8080", nil))
2.2 示例
package main import ( "fmt" "net/http" ) func sayHello(w http.ResponseWriter, r *http.Request) { defer r.Body.Close() fmt.Fprintln(w, "hello 張三") } func main() { http.HandleFunc("/", sayHello) err := http.ListenAndServe(":8080", nil) if err != nil { fmt.Println("http server fail, err ", err) return } }
2.3 自定義Server
type Server struct { Addr string // 監(jiān)聽(tīng)的TCP地址,如果為空字符串會(huì)使用":http" Handler Handler // 調(diào)用的處理器,如為nil會(huì)調(diào)用http.DefaultServeMux ReadTimeout time.Duration // 請(qǐng)求的讀取操作在超時(shí)前的最大持續(xù)時(shí)間 WriteTimeout time.Duration // 回復(fù)的寫(xiě)入操作在超時(shí)前的最大持續(xù)時(shí)間 MaxHeaderBytes int // 請(qǐng)求的頭域最大長(zhǎng)度,如為0則用DefaultMaxHeaderBytes TLSConfig *tls.Config // 可選的TLS配置,用于ListenAndServeTLS方法 // TLSNextProto(可選地)指定一個(gè)函數(shù)來(lái)在一個(gè)NPN型協(xié)議升級(jí)出現(xiàn)時(shí)接管TLS連接的所有權(quán)。 // 映射的鍵為商談的協(xié)議名;映射的值為函數(shù),該函數(shù)的Handler參數(shù)應(yīng)處理HTTP請(qǐng)求, // 并且初始化Handler.ServeHTTP的*Request參數(shù)的TLS和RemoteAddr字段(如果未設(shè)置)。 // 連接在函數(shù)返回時(shí)會(huì)自動(dòng)關(guān)閉。 TLSNextProto map[string]func(*Server, *tls.Conn, Handler) // ConnState字段指定一個(gè)可選的回調(diào)函數(shù),該函數(shù)會(huì)在一個(gè)與客戶端的連接改變狀態(tài)時(shí)被調(diào)用。 // 參見(jiàn)ConnState類(lèi)型和相關(guān)常數(shù)獲取細(xì)節(jié)。 ConnState func(net.Conn, ConnState) // ErrorLog指定一個(gè)可選的日志記錄器,用于記錄接收連接時(shí)的錯(cuò)誤和處理器不正常的行為。 // 如果本字段為nil,日志會(huì)通過(guò)log包的標(biāo)準(zhǔn)日志記錄器寫(xiě)入os.Stderr。 ErrorLog *log.Logger // 內(nèi)含隱藏或非導(dǎo)出字段 }
要管理服務(wù)端的行為,可以創(chuàng)建一個(gè)自定義的Server:
s := &http.Server{ Addr: ":8080", Handler: myHander, ReadTimeout: 10 * time.Second, WriteTimeout: 10 * time.Second, MaxHeaderBytes: 1 << 20, }
到此這篇關(guān)于Golang中http包的具體使用的文章就介紹到這了,更多相關(guān)Golang http包內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Go語(yǔ)言O(shè)RM框架構(gòu)造查詢條件示例詳解
這篇文章主要為大家介紹了Go語(yǔ)言O(shè)RM框架構(gòu)造查詢條件示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-12-12Golang連接池的幾種實(shí)現(xiàn)案例小結(jié)
這篇文章主要介紹了Golang連接池的幾種實(shí)現(xiàn)案例小結(jié),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-03-03