go语言发送http请求

2,381 阅读3分钟

http协议

知识结构图如下:

详细内容请看:一篇文章带你详解 HTTP 协议

请求和响应报文结构

我们在与http打交道时,见得最多的就是请求和响应报文了,通过报文来学习http协议再好不过了,每次看见报文的时候,就相当于一次复习,那么我们接下来就来学习如何读懂报文

请求报文结构图

实例:

响应报文结构图

实例:

两种报文都是由三部分组成,但是他们的各三部分的名字都不相同:

请求报文:请求行,请求头部,请求数据

响应报文:状态行,首部行,实体

Content-Type的含义

在使用go语言发送HTTP请求的时候,content-type设置的不对,服务器将接收不到参数,所以特意将这个属性拎出来讲。

当客户端向服务端发起HTTP的POST请求时,需要告诉服务端,我们发送的数据类型,方便服务端去解析数据。如果你不设置,那么服务端可能无法处理你的请求。

含义:Content-Type 说明了实体主体内对象的媒体类型

常见的媒体格式类型如下:
text/html   :   HTML格式 
text/plain  :   纯文本格式       
text/xml    :   XML格式 
image/gif   :   gif图片格式     
image/jpeg  :   jpg图片格式  
image/png   :   png图片格式
form表单发送post请求有三种 Content-Type

application/x-www-form-urlencoded

multipart/form-data

text/plain

  1. application/x-www-form-urlencoded

    用于普通字段的表单数据,表单数据会在请求体中,数据以符合application/x-www-form-urlencoded格式发送给服务端。

  2. multipart/form-data

    用于文件或二进制数据,数据会按照某种格式(就是multipart/form-data这种格式啦,这真不是废话),你想知道这种格式具体是什么样的就看MDN,因为这并不是重点,就是一种格式而已。

  3. text/plain

    永远不要使用这个值,因为不会被可靠的去解析。

操作性最高的 client.Do 的方式发送请求

步骤:

  1. 包装参数

  2. 生成 request

  3. 生成 client

  4. client.Do

  5. 解析请求返回值

例码:

POST请求

func main(){
    //	注意这里将参数解析成reader的方式 POST请求方式使用
    v:=make(url.Values,0)
	v["code"] = []string{"lkjshdlfkjghlksjdhflgkjhsdlkg"}
	v["wx_nick"] = []string{"lkjshdlfkjghlksjdhflgkjhsdlkg"}
	v["wx_image"] = []string{"lkjshdlfkjghlksjdhflgkjhsdlkg"}

	s:=v.Encode()
	fmt.Println(s)
	data:=strings.NewReader(s)

    //	生成request
    url:=baseURL01+"index"
	request,err:=http.NewRequest(http.MethodPost,url,data)
	if err!=nil{
		fmt.Println("NewRequest error: ",err)
		return
	}

    //	这个请求头的Content-type是如何对应 gin框架的解析参数的方式的?
	//		application/x-www-form-urlencoded => c.PostForm  c.Request.FormValue
	//		multipart/form-data		=>		c.FormFile	c.Request.FormFile
	//		application/json		=>		c.Query		Get请求时用
	request.Header.Set("Content-type", "application/x-www-form-urlencoded")

    //	发起请求,并解析返回数据
    client:= &http.Client{}
	res,err:=client.Do(request)
	if err!=nil{
		fmt.Println("client.Do error: ",err)
		return
	}

	defer res.Body.Close()
	da,err:=ioutil.ReadAll(res.Body)
	if err!=nil{
		fmt.Println("ioutil.ReadAll error: ",err)
		return
	}

	fmt.Println(string(da))
}

GET请求

func main(){
 	//	这里只展示参数处理方式   
    params := url.Values{}
    ur, err := url.Parse("https://127.0.0.1/index")
	if err != nil {
		return 
	}

    //	这里只是演示data是什么
    data:=make(map[string]string,0)
	for key, value := range data {
		params.Set(key, value)
	}

	//	生成请求路径
	ur.RawQuery = params.Encode()
	urlPath := ur.String()

    …… 代码同上
}

顺便记录下更简单的Get请求例子:

func GetUrl(url string, data map[string]string) ([]byte) {
	params := u.Values{}
	ur, err := u.Parse(url)
	if err != nil {
		return nil
	}

	for key, value := range data {
		params.Set(key, value)
	}

	//	生成请求路径
	ur.RawQuery = params.Encode()
	urlPath := ur.String()

	res, _ := http.Get(urlPath)
	defer res.Body.Close()

	//	将json
	d, err := ioutil.ReadAll(res.Body)
	if err != nil {
		return nil
	}
	return d
}