1. Client结构体

1.1 从一个极简示例开始

先写一个Get的极简示例,访问gitlab的所有项目(因为极简示例没有加token,因此只能获取到gitlab中开放的项目)

func HiHttp(){
	resp, err := http.Get("http://gitlabcto.xxx.com.cn/api/v4/projects")
	if err != nil {
		// handle error
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
    //body是一个二进制组,用string(body[:])转换为字串
	fmt.Printf("%s",string(body[:]))
}

1.2 结构体定义

type Client struct {
    Transport     RoundTripper
    CheckRedirect func(req *Request, via []*Request) error
    Jar           CookieJar
    Timeout       time.Duration
}

1.3 包含的方法

Client结构体有以下方法:

send(req *http.Request, deadline time.Time) (resp *http.Response, didTimeout func() bool, err error)
deadline() time.Time
transport() http.RoundTripper
Get(url string) (resp *http.Response, err error)
checkRedirect(req *http.Request, via []*http.Request) error
Do(req *http.Request) (*http.Response, error)
do(req *http.Request) (retres *http.Response, reterr error)
makeHeadersCopier(ireq *http.Request) func(*http.Request)
Post(url string, contentType string, body io.Reader) (resp *http.Response, err error)
PostForm(url string, data url.Values) (resp *http.Response, err error)
Head(url string) (resp *http.Response, err error)
CloseIdleConnections()

我们会在后文详细叙述

1.4 初始化结构体

var DefaultClient = &http.Client{}
  • 示例
func HiHttp(){
	var myClient = &http.Client{} 
	resp, err := myClient.Get("http://gitlabcto.xxx.com.cn/api/v4/projects")
	if err != nil {
		fmt.Println(err)
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	fmt.Printf("%s",string(body[:]))
}
2. Get() 方法

2.1 语法

1.2.1 Get方法

语法

func Get(url string) (resp *Response, err error)

示例

resp, err := http.Get("http://xxxx.xxx.com")

2.1.1 url

  • 将字串转换为URL

非必要,如果后边url要拼参数的话可以用这个

func ParseRequestURI(rawURL string) (*URL, error)
  • 示例
apiUrl := "http://gitlabcto.xxx.com.cn/api/v4/projects"
u,err := url.ParseRequestURI(apiUrl)

2.1.2 params(参数)

作用:在url后拼接参数

初始化

data := url.Values{}

设定参数

data.Set("key","value")

将参数添加到url

u.RawQuery = data.Encode()

u是上文中初始化的url

2.2 示例(不自定义header)

func HiHttp(){
	apiUrl := "http://gitlabcto.xxx.com.cn/api/v4/projects"
	// URL param
	data := url.Values{}
	data.Set("private_token", "-raXU2B8rVbRAFxxxxxx")
	data.Set("per_page", "100")
	data.Set("page", "30")
	//把string转换为url
	u, err := url.ParseRequestURI(apiUrl)
	if err != nil {
		fmt.Printf("parse url requestUrl failed,err:%v\n", err)
	}
	//将参数添加到请求url
	u.RawQuery = data.Encode() // URL encode
	fmt.Println(u.String())
	resp, err := http.Get(u.String())
	if err != nil {
		fmt.Println("post failed, err:%v\n", err)
		return
	}
	defer resp.Body.Close()
	b, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		fmt.Println("get resp failed,err:%v\n", err)
		return
	}
	fmt.Println(string(b))
}
3. Post()方法

注意:此处是http包提供的一个简单的post方法,不能添加header,如果要添加header需要使用Do()方法。

3.1 语法

3.1.1 Post()方法

func Post(url string, contentType string, body io.Reader) (resp *Response, err error)

示例

http.Post(url, contentType, strings.NewReader(data))

body的定义,参见本文 Do()方法

3.1.2 contentType

表单格式

	contentType := "application/x-www-form-urlencoded"
	data := "key01=value01&key02=value02"
&

json格式

	contentType := "application/json"
	data := `{"project_name": "liuBei","metadata": {"public": "true"}}`

3.2 示例(不添加header)

  • 因为http包的Post() 方法没有header,因此harbor的认证是过不去的。
  • 建议使用Do()方法
func PostHttp(){
	url := "https://harbocto.xxx.com.cn/api/v2.0/projects"
	contentType := "application/json"
	data := `{"project_name": "liuBei","metadata": {"public": "true"}}`
	resp, err := http.Post(url, contentType, strings.NewReader(data))
	if err != nil {
		fmt.Printf("err: %v\n", err)
		return
	}
	defer resp.Body.Close()
	b, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		fmt.Printf("err: %v\n", err)
		return
	}
	fmt.Println(string(b))
}
4. Do() 方法

4.1 语法

4.1.1 Do()方法

func (c *Client) Do(req *Request) (*Response, error)

示例

resp, _ := client.Do(req)
request

4.1.2 NewRequest

语法

func NewRequest(method string, url string, body io.Reader) (*Request, error)

示例:Get 方法,没有body的情况

req, err := http.NewRequest("GET", ""https://xxxx.xxxx.com.cn", nil)

示例:Post方法,body是json字串

req, err := http.NewRequest("POST", url, strings.NewReader(`{"project_name": "liubei","metadata": {"public": "true"}}`)

示例:Post方法,body是[]byte

var js []byte = xxxxxx
req, err := http.NewRequest("POST", url, bytes.NewBuffer(js))

4.1.3 Header 添加头信息

Set 函数

相同key的值会被替换为最新的

  • 语法
func (h Header) Set(key string, value string)
  • 示例
	req.Header.Set("aaa", "111")
	req.Header.Set("aaa", "222")
	req.Header.Set("aaa", "333")
	fmt.Printf("%+v\n",req.Header)

输出

map[Aaa:[333] Authorization:[Basic 5YiY5aSHOuaIkeS4jeS8muWRiuivieS9oOWvhueggQ== ] Content-Type:[application/json]]

Add 函数

相同key的值会被追加

  • 语法
func (h Header) Add(key string, value string)
  • 示例
	req.Header.Add("aaa", "111")
	req.Header.Add("aaa", "222")
	req.Header.Add("aaa", "333")
	fmt.Printf("%+v\n",req.Header)

输出

map[Aaa:[111 222 333] Authorization:[Basic 5YiY5aSHOuaIkeS4jeS8muWRiuivieS9oOWvhueggQ==] Content-Type:[application/json]]

4.1.4 Query

定义Query

func (u *URL) Query() Values

示例

req, err := http.NewRequest("GET", ""https://xxxx.xxxx.com.cn", nil)
q := req.URL.Query()

添加 Query

func (v Values) Add(key string, value string)

示例

定义q 见定义Query

	q.Add("per_page", "3")
	q.Add("page", "1")

4.2 示例(添加header)

func GetHttpWithHeader(){
	client := &http.Client{}
	apiURL := "https://harbocto.xxxx.com.cn/api/v2.0/projects/9"

	req, err := http.NewRequest("GET", apiURL, nil)
	if err != nil {
		fmt.Printf("err: %v\n", err)
		return
	}
	req.Header.Add("Authorization", "Basic 5YiY5aSHOuaIkeS4jeS8muWRiuivieS9oOWvhueggQ==")
	req.Header.Add("Content-Type", "application/json")

	resp, _ := client.Do(req)
	defer resp.Body.Close()
	b, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		fmt.Printf("get resp failed,err:%v\n\n", err)
		return
	}
	fmt.Println(string(b))
}

4.3 示例(Get请求,添加Query)

func GetHttp(){
	client := &http.Client{}
	apiURL := "http://gitlabcto.xxx.com.cn/api/v4/projects"

	req, err := http.NewRequest("GET", apiURL, nil)
	//添加查询参数
	q := req.URL.Query()
	q.Add("private_token", "-raXU2B8rVbRAFdYEqEg")
	q.Add("per_page", "3")
	q.Add("page", "1")
	req.URL.RawQuery = q.Encode()
	fmt.Println(req.URL.String())

	req.Header.Add("Content-Type", "application/json")

	if err != nil {
		fmt.Printf("post failed, err:%v\n\n", err)
		return
	}
	resp, _ := client.Do(req)
	defer resp.Body.Close()
	b, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		fmt.Printf("get resp failed,err:%v\n\n", err)
		return
	}
	fmt.Println(string(b))
}

4.4 示例(Post请求,application/json)

func PostHttpWithJson() {
	client := &http.Client{}
	url := "https://harbocto.xxx.com.cn/api/v2.0/projects"
	data := `{"project_name": "liubei","metadata": {"public": "true"}}`
	req, err := http.NewRequest("POST", url, strings.NewReader(data))
	if err != nil {
		fmt.Printf("err: %v\n", err)
	}
	req.Header.Set("Content-Type", "application/json")
	req.Header.Add("Authorization", "Basic 5YiY5aSHOuaIkeS4jeS8muWRiuivieS9oOWvhueggQ==")

	resp,err := client.Do(req)
	if err != nil {
	fmt.Printf("err: %v\n", err)
	}
	fmt.Printf("执行状态为:%d",resp.StatusCode)

}

4.5 示例 (post请求,body使用定义的结构体)

type MyBody struct {
	ProjectName string `json:"project_name"`
	Metadata    struct {
		Public string `json:"public"`
	} `json:"metadata"`
}

func PostHttpWithStruct() {
	client := &http.Client{}
	url := "https://harbocto.xxx.com.cn/api/v2.0/projects"

	var s  MyBody
	s.ProjectName = "liubei-01"
	s.Metadata.Public = "true"

	js, err := json.MarshalIndent(&s, "", "\t")
	fmt.Println(string(js))
	req, err := http.NewRequest("POST", url, bytes.NewBuffer(js))
	if err != nil {
		fmt.Printf("err: %v\n", err)
		return
	}

	req.Header.Set("Authorization", "Basic 5YiY5aSHOuaIkeS4jeS8muWRiuivieS9oOWvhueggQ==")
	req.Header.Set("Content-Type", "application/json")

	resp, _ := client.Do(req)
	defer resp.Body.Close()

	fmt.Printf("执行状态为:%d",resp.StatusCode)

}