go http


原文链接: go http

Golang提供了官方的http包,对于http操作非常的方便和简洁。
但是不同于PHP,使用Golang的包来做http操作,还是没有那么”直接“,需要实例化一下这个,实例化一下那个,有点像Java,因此,为了以后书写方便,就把基本的请求写在此。下次用的时候,直接copy就好了。

[](https://i6448038.github.io/2017/11/11/httpAndGolang/#get-%E8%AF%B7%E6%B1%82 "get 请求")get 请求

get请求有好几种方式

[](https://i6448038.github.io/2017/11/11/httpAndGolang/#%E7%9B%B4%E6%8E%A5%E4%BD%BF%E7%94%A8net-http%E5%8C%85%E5%86%85%E7%9A%84%E5%87%BD%E6%95%B0%E8%AF%B7%E6%B1%82 "直接使用net/http包内的函数请求")直接使用net/http包内的函数请求

    import "net/http"  
    ...  
    resp, err := http.Get("http://wwww.baidu.com")  

[](https://i6448038.github.io/2017/11/11/httpAndGolang/#%E5%88%A9%E7%94%A8http-client%E7%BB%93%E6%9E%84%E4%BD%93%E6%9D%A5%E8%AF%B7%E6%B1%82 "利用http.client结构体来请求")利用http.client结构体来请求

    import "net/http"  
    ...  
    clt := http.Client{}  
    resp, err := clt.Get("http://wwww.baidu.com")  

[](https://i6448038.github.io/2017/11/11/httpAndGolang/#%E6%9C%80%E6%9C%AC%E8%B4%A8%E7%9A%84%E8%AF%B7%E6%B1%82%E6%96%B9%E5%BC%8F "最本质的请求方式")最本质的请求方式

如果稍微看一下源码,就会发现以上两种方式都是用了一下这种最本质的请求方式,使用http.NewRequest函数

    req, err := http.NewRequest("GET", "http://www.baidu.com", nil)  

    //然后http.client 结构体的 Do 方法  
    //http.DefaultClient可以换为另外一个http.client  
    resp, err := http.DefaultClient.Do(req)  

Go的get请求面上有好几种请求方式,实则只有一种:

1、使用http.NewRequest函数获得request实体

2、利用http.client结构体的Do方法,将request实体传入Do方法中。

[](https://i6448038.github.io/2017/11/11/httpAndGolang/#post%E8%AF%B7%E6%B1%82 "post请求")post请求

和get请求类似,post请求也有多种方法,但本质还是使用了http.NewRequest函数和http.clientDo方法。

[](https://i6448038.github.io/2017/11/11/httpAndGolang/#%E4%BD%BF%E7%94%A8net-http%E5%8C%85%E5%B8%A6%E7%9A%84post%E6%96%B9%E6%B3%95 "使用net/http包带的post方法")使用net/http包带的post方法

    import (  
    "net/http"  
    "net/url"  
    )  
    ...  
    data := url.Values{"start":{"0"}, "offset":{"xxxx"}}  
    body := strings.NewReader(data.Encode())  
    resp, err := http.Post("xxxxxxx", "application/x-www-form-urlencoded", body)  

或者还可以

    import (  
    "net/http"  
    "net/url"  
    )  
    ...  
    var r http.Request  
    r.ParseForm()  
    r.Form.Add("xxx", "xxx")  
    body := strings.NewReader(r.Form.Encode())  
    http.Post("xxxx", "application/x-www-form-urlencoded", body)  

要是还是觉得复杂,还可以:

    import (  
    "net/http"  
    "net/url"  
    )  
    ...  
    data := url.Values{"start":{"0"}, "offset":{"xxxx"}}  
    http.PostForm("xxxx", data)  

[](https://i6448038.github.io/2017/11/11/httpAndGolang/#%E4%BD%BF%E7%94%A8%E5%AE%9E%E4%BE%8B%E5%8C%96%E7%9A%84http-client%E7%9A%84post%E6%96%B9%E6%B3%95 "使用实例化的http client的post方法")使用实例化的http client的post方法

其实本质上直接使用包的函数和实例化的http client是一样的,包的函数底层也仅仅是实例化了一个DefaultClient,然后调用的DefaultClient的方法。下面给出使用实例化的http client的post方法:

    import (  
    "net/http"  
    "net/url"  
    )  
    ...  
    data := url.Values{"start":{"0"}, "offset":{"xxxx"}}  
    body := strings.NewReader(data.Encode())  
    clt := http.Client{}  
    resp, err := clt.Post("xxxxxxx", "application/x-www-form-urlencoded", body)  

还有

    import (  
    "net/http"  
    "net/url"  
    )  
    ...  
    var r http.Request  
    r.ParseForm()  
    r.Form.Add("xxx", "xxx")  
    body := strings.NewReader(r.Form.Encode())  
    clt := http.Client{}  
    clt.Post("xxxx", "application/x-www-form-urlencoded", body)  

简单的,但仅限于form表单

    import (  
    "net/http"  
    "net/url"  
    )  
    ...  
    data := url.Values{"start":{"0"}, "offset":{"xxxx"}}  
    clt := http.Client{}  
    clt.PostForm("xxxx", data)  

[](https://i6448038.github.io/2017/11/11/httpAndGolang/#%E4%BD%BF%E7%94%A8net-http%E5%8C%85%E7%9A%84NewRequest%E5%87%BD%E6%95%B0 "使用net/http包的NewRequest函数")使用net/http包的NewRequest函数

其实不管是get方法也好,post方法也好,所有的get、post的的http 请求形式,最终都是会调用net/http包的NewRequest函数,多种多样的请求形式,也仅仅是封装的不同而已。

    import (  
    "net/http"  
    "net/url"  
    )  
    ...  

    data := url.Values{"start":{"0"}, "offset":{"xxxx"}}  
    body := strings.NewReader(data.Encode())  

    req, err := http.NewRequest("POST", "xxxxx", body)  
    req.Header.Set("Content-Type", "application/x-www-form-urlencoded")  

    clt := http.Client{}  
    clt.Do(req)  

[](https://i6448038.github.io/2017/11/11/httpAndGolang/#%E6%B7%BB%E5%8A%A0request-header "添加request header")添加request header

net/http包没有封装直接使用请求带header的get或者post方法,所以,要想请求中带header,只能使用NewRequest方法。

    import (  
    "net/http"  

    )  
    ...  

    req, err := http.NewRequest("POST", "xxxxx", body)  
    //此处还可以写req.Header.Set("User-Agent", "myClient")  
    req.Header.Add("User-Agent", "myClient")  

    clt := http.Client{}  
    clt.Do(req)  

有一点需要注意:在添加header操作的时候,req.Header.Addreq.Header.Set都可以,但是在修改操作的时候,只能使用req.Header.Set
这俩方法是有区别的,Golang底层Header的实现是一个map[string][]stringreq.Header.Set方法如果原来Header中没有值,那么是没问题的,如果又值,会将原来的值替换掉。而req.Header.Add的话,是在原来值的基础上,再append一个值,例如,原来header的值是“s”,我后req.Header.Add一个”a”的话,变成了[s a]。但是,获取header值的方法req.Header.Get确只取第一个,所以,如果原来有值,重新req.Header.Add一个新值的话,req.Header.Get得到的值不变。

[](https://i6448038.github.io/2017/11/11/httpAndGolang/#%E6%89%93%E5%8D%B0response%E5%93%8D%E5%BA%94 "打印response响应")打印response响应

Golang打印response没有PHP那么爽,哎,编译型语言就是麻烦。

    import (  
    	"net/http"  
    	"net/url"  
    	"io/ioutil"  
    )  
    ...  
    content, err := ioutil.ReadAll(resp.Body)  
    respBody := string(content)  

[](https://i6448038.github.io/2017/11/11/httpAndGolang/#%E4%BD%BF%E7%94%A8cookie "使用cookie")使用cookie

Golang提供了cookie的包net/http/cookiejar


    url, err := url.Parse("https://www.wukong.com/")  
    jar, err := cookiejar.New(nil)  
    jar.SetCookies(url, cookies)//这里的cookies是[]*http.Cookie  
    wukongClt := http.Client{Transport:nil, Jar:jar}  

    wukongClt.Get("xxxxx")  

文中的cookies类型是[] *http.cookie可以自己实例化,有时候也可以从response中直接使用resp.Cookies()直接拿到。

Golang的cookie是和http.client联系在一起的,作为http.client的一个属性存在。因此,要想在Golang中使用cookie,就必须想办法构造http.client

[](https://i6448038.github.io/2017/11/11/httpAndGolang/#%E4%BD%BF%E7%94%A8%E4%BB%A3%E7%90%86 "使用代理")使用代理

在Golang中使用http proxy,也必须构造自己的http.client,需要将http.client结构体的一个属性Transport自己实例化好。

[](https://i6448038.github.io/2017/11/11/httpAndGolang/#%E5%BD%93%E4%BD%BF%E7%94%A8%E7%8E%AF%E5%A2%83%E5%8F%98%E9%87%8F-http-proxy%E6%88%96-HTTP-PROXY%E4%BD%9C%E4%B8%BA%E4%BB%A3%E7%90%86%E6%97%B6 "当使用环境变量$http_proxy或$HTTP_PROXY作为代理时")当使用环境变量$http_proxy或$HTTP_PROXY作为代理时

    //从环境变量$http_proxy或$HTTP_PROXY中获取HTTP代理地址  
    func GetTransportFromEnvironment() (transport *http.Transport) {  
    	transport = &http.Transport{Proxy : http.ProxyFromEnvironment}  
    	return  
    }  

[](https://i6448038.github.io/2017/11/11/httpAndGolang/#%E5%BD%93%E4%BD%BF%E7%94%A8%E8%87%AA%E5%B7%B1%E6%90%AD%E5%BB%BAhttp%E4%BB%A3%E7%90%86%E6%97%B6 "当使用自己搭建http代理时")当使用自己搭建http代理时

参数proxy_addr即代理服务器IP端口号,例如:”http://xxx.xxx.xxx.xxx:6000“,注意,必须加上"http"

    func GetTransportFieldURL(proxy_addr *string) (transport *http.Transport) {  
    	url_i := url.URL{}  
    	url_proxy, error := url_i.Parse(*proxy_addr)  
    	if error != nil{  
    		fmt.Println(error.Error())  
    	}  
    	transport = &http.Transport{Proxy : http.ProxyURL(url_proxy)}  
    	return  
    }  

使用的时候,首先调用函数,拿到对应的transport,即使用GetTransportFieldURL或者GetTransportFieldURL函数,然后构建自定义的http.client :

    ProxyUrl := "http://xxx.xxx.xxx.xxx:6000"  
    transport := GetTransportFieldURL(&ProxyUrl)  
    clt := http.Client{Transport:transport}  

    clt.Get("http://www.baidu.com")
`