func (c *Client) Get(url string) (r *Response, err error)
func (c *Client) Post(url string, bodyType string, body io.Reader) (r *Response, err error)
func (c *Client) PostForm(url string, data url.Values) (r *Response, err error)
func (c *Client) Head(url string) (r *Response, err error)
func (c *Client) Do(req *Request) (resp *Response, err error)
package main import ( "fmt" "io/ioutil" "net/http" ) func main() { resp, err := http.Get("http://c.biancheng.net") if err != nil { fmt.Println(err) } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) fmt.Println(string(body)) }上面這段程式碼請求一個網站首頁,並將其網頁內容列印出來,如下所示:
<!DOCTYPE html>
<html lang="zh-cn">
<head>
......
</head>
<body>
......
</body>
</html>
func Get(url string) (resp *Response, err error) {
return DefaultClient.Get(url)
}
var DefaultClient = &Client{}
它是 net/http 包公開屬性,當我們在 http 上呼叫 Get、Post、PostForm、Head 方法時,最終呼叫的都是該物件上的對應方法。resp, err := http.Post("http://c.biancheng.net/upload", "image/jpeg", &buf) if err != nil { fmt.Println(err) } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { fmt.Println(err) } fmt.Println(string(body))其中 &buf 為圖片的資源。
package main import ( "fmt" "io/ioutil" "net/http" "net/url" ) func main() { resp, err := http.PostForm("http://www.baidu.com", url.Values{"wd": {"golang"}}) if err != nil { fmt.Println(err) } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { fmt.Println(err) } fmt.Println(string(body)) }注意:POST 請求引數需要通過 url.Values 方法進行編碼和封裝。
package main import ( "fmt" "net/http" ) func main() { resp, err := http.Head("http://c.biancheng.net") if err != nil { fmt.Println("Request Failed: ", err.Error()) return } defer resp.Body.Close() // 列印頭資訊 for key, value := range resp.Header { fmt.Println(key, ":", value) } }執行結果如下:
go run main.go
X-Swift-Savetime : [Thu, 02 Jan 2020 02:12:51 GMT]
X-Swift-Cachetime : [31104000]
Content-Type : [text/html]
......
Via : [cache12.l2cn2178[13,200-0,M], cache10.l2cn2178[14,0], kunlun9.cn1481[0,200-0,H], kunlun8.cn1481[1,0]]
X-Cache : [HIT TCP_MEM_HIT dirn:11:355030002]
package main import ( "fmt" "io" "net/http" "os" ) func main() { // 初始化用戶端請求物件 req, err := http.NewRequest("GET", "http://c.biancheng.net", nil) if err != nil { fmt.Println(err) return } // 新增自定義請求頭 req.Header.Add("Custom-Header", "Custom-Value") // 其它請求頭設定 client := &http.Client{ // 設定用戶端屬性 } resp, err := client.Do(req) if err != nil { fmt.Println(err) return } defer resp.Body.Close() io.Copy(os.Stdout, resp.Body) }執行結果如下:
<!DOCTYPE html>
<html lang="zh-cn">
<head>
......
</head>
<body>
......
</body>
</html>
type Client struct { // Transport 用於確定HTTP請求的建立機制。 // 如果為空,將會使用DefaultTransport Transport RoundTripper // CheckRedirect定義重定向策略。 // 如果CheckRedirect不為空,用戶端將在跟蹤HTTP重定向前呼叫該函數。 // 兩個引數req和via分別為即將發起的請求和已經發起的所有請求,最早的 // 已發起請求在最前面。 // 如果CheckRedirect返回錯誤,用戶端將直接返回錯誤,不會再發起該請求。 // 如果CheckRedirect為空,Client將採用一種確認策略,將在10個連續 // 請求後終止 CheckRedirect func(req *Request, via []*Request) error // 如果Jar為空,Cookie將不會在請求中傳送,並會 // 在響應中被忽略 Jar CookieJar }在Go語言標準庫中,http.Client 型別包含了 3 個公開資料成員:
Transport RoundTripper
CheckRedirect func(req *Request, via []*Request) error
Jar CookieJar
client := &http.Client { CheckRedirect: redirectPolicyFunc, } resp, err := client.Get("http://example.com") // ... req, err := http.NewRequest("GET", "http://example.com", nil) // ... req.Header.Add("User-Agent", "Our Custom User-Agent") req.Header.Add("If-None-Match", `W/"TheFileEtag"`) resp, err := client.Do(req) // ...
type Transport struct { // Proxy指定用於針對特定請求返回代理的函數。 // 如果該函數返回一個非空的錯誤,請求將終止並返回該錯誤。 // 如果Proxy為空或者返回一個空的URL指標,將不使用代理 Proxy func(*Request) (*url.URL, error) // Dial指定用於建立TCP連線的dail()函數。 // 如果Dial為空,將預設使用net.Dial()函數 Dial func(net, addr string) (c net.Conn, err error) // TLSClientConfig指定用於tls.Client的TLS設定。 // 如果為空則使用預設設定 TLSClientConfig *tls.Config DisableKeepAlives bool DisableCompression bool // 如果MaxIdleConnsPerHost為非零值,它用於控制每個host所需要 // 保持的最大空閒連線數。如果該值為空,則使用DefaultMaxIdleConnsPerHost MaxIdleConnsPerHost int // ... }在上面的程式碼中,我們定義了 http.Transport 型別中的公開資料成員,下面詳細說明其中的各行程式碼。
Proxy func(*Request) (*url.URL, error)
Proxy 指定了一個代理方法,該方法接受一個 *Request 型別的請求範例作為引數並返回一個最終的 HTTP 代理。如果 Proxy 未指定或者返回的 *URL 為零值,將不會有代理被啟用。Dial func(net, addr string) (c net.Conn, err error)
Dial 指定具體的 dial() 方法來建立 TCP 連線。如果不指定,預設將使用 net.Dial() 方法。TLSClientConfig *tls.Config
SSL 連線專用,TLSClientConfig 指定 tls.Client 所用的 TLS 設定資訊,如果不指定,也會使用預設的設定。DisableKeepAlives bool
是否取消長連線,預設值為 false,即啟用長連線。DisableCompression bool
是否取消壓縮(GZip),預設值為 false,即啟用壓縮。MaxIdleConnsPerHost int
指定與每個請求的目標主機之間的最大非活躍連線(keep-alive)數量。如果不指定,預設使用 DefaultMaxIdleConnsPerHost 的常數值。tr := &http.Transport{ TLSClientConfig: &tls.Config{RootCAs: pool}, DisableCompression: true, } client := &http.Client{Transport: tr} resp, err := client.Get("https://example.com")Client 和 Transport 在執行多個 goroutine 的併行過程中都是安全的,但出於效能考慮,應當建立一次後反復使用。
type RoundTripper interface { // RoundTrip執行一個單一的HTTP事務,返回相應的響應資訊。 // RoundTrip函數的實現不應試圖去理解響應的內容。如果RoundTrip得到一個響應, // 無論該響應的HTTP狀態碼如何,都應將返回的err設定為nil。非空的err // 只意味著沒有成功獲取到響應。 // 類似地,RoundTrip也不應試圖處理更高階別的協定,比如重定向、認證和 // Cookie等。 // // RoundTrip不應修改請求內容, 除非了是為了理解Body內容。每一個請求 // 的URL和Header域都應被正確初始化 RoundTrip(*Request) (*Response, error) }從上述程式碼中可以看到,http.RoundTripper 介面很簡單,只定義了一個名為 RoundTrip 的方法。任何實現了 RoundTrip() 方法的型別即可實現 http.RoundTripper 介面。前面我們看到的 http.Transport 型別正是實現了 RoundTrip() 方法繼而實現了該介面。
package main import( "net/http" ) type OurCustomTransport struct { Transport http.RoundTripper } func (t *OurCustomTransport) transport() http.RoundTripper { if t.Transport != nil { return t.Transport } return http.DefaultTransport } func (t *OurCustomTransport) RoundTrip(req *http.Request) (*http.Response, error) { // 處理一些事情 ... // 發起HTTP請求 // 新增一些域到req.Header中 return t.transport().RoundTrip(req) } func (t *OurCustomTransport) Client() *http.Client { return &http.Client{Transport: t} } func main() { t := &OurCustomTransport{ //... } c := t.Client() resp, err := c.Get("http://example.com") // ... }因為實現了 http.RoundTripper 介面的程式碼通常需要在多個 goroutine 中並行執行,因此我們必須確保實現程式碼的執行緒安全性。