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
-
application/x-www-form-urlencoded
用于普通字段的表单数据,表单数据会在请求体中,数据以符合
application/x-www-form-urlencoded格式发送给服务端。 -
multipart/form-data
用于文件或二进制数据,数据会按照某种格式(就是multipart/form-data这种格式啦,这真不是废话),你想知道这种格式具体是什么样的就看MDN,因为这并不是重点,就是一种格式而已。
-
text/plain
永远不要使用这个值,因为不会被可靠的去解析。
操作性最高的 client.Do 的方式发送请求
步骤:
-
包装参数
-
生成 request
-
生成 client
-
client.Do
-
解析请求返回值
例码:
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
}