非零基础自学Golang 第17章 HTTP编程(上) 17.2 HTTP客户端 17.2.2 Client 和 Request
非零基础自学Golang
文章目录
- 非零基础自学Golang
- 第17章 HTTP编程(上)
- 17.2 HTTP客户端
- 17.2.2 Client 和 Request
第17章 HTTP编程(上)
17.2 HTTP客户端
17.2.2 Client 和 Request
学习HTTP客户端,我们需要理解和掌握两个非常重要的类型,一个是Client,另一个是Request。
首先,我们来看一下Client的结构体类型。
type Client struct {
Transport RoundTripper
CheckRedirect func(req *Request, via []*Request) error
Jar CookieJar
Timeout time.Duration
}
Client的结构相对较为简单,只有四个成员,分别是Transport、CheckRedirect、Jar和Timeout。
- Transport指定执行独立、单次HTTP请求的机制。如果Transport为nil,则使用DefaultTransport。
- CheckRedirect指定处理重定向的策略。如果CheckRedirect不为nil,客户端会在执行重定向之前调用本函数字段。参数req和via是将要执行的请求和已经执行的请求(切片,越新的请求越靠后)。如果CheckRedirect返回一个错误,本类型的GET方法不会发送请求req,而是返回之前得到的最后一个回复和该错误(包装进url.Error类型里)。如果CheckRedirect为nil,会采用默认策略:连续十次请求后停止。
- Jar指定Cookie管理器。如果Jar为nil,请求中不会发送Cookie,回复中的Cookie会被忽略。
- Timeout指定本类型的值执行请求的时间限制。该超时限制包括连接时间、重定向和读取回复主体的时间。计时器会在Head、Get、Post或Do方法返回后继续运作,并在超时后中断回复主体的读取。Timeout为零值表示不设置超时。
Client类型主要充当浏览器的角色,它拥有如下方法:
func (c *Client) Do(req *Request) (resp *Response, err error)
func (c *Client) Head(url string) (resp *Response, err error)
func (c *Client) Get(url string) (resp *Response, err error)
func (c *Client) Post(url string, bodyType string, body io.Reader) (resp *Response, err error)
func (c *Client) PostForm(url string, data url.Values) (resp *Response, err error)
上述方法中最重要的是Do方法,其他的方法GET、POST等都是基于Do方法的封装,这些方法的具体使用我们后面细说。
除了Client类型,我们还需要了解Request类型。Request主要是对请求体的封装,任何形式的HTTP请求都可以使用Request来构造,构造完后使用Client端发送请求。
Request的结构体如下:
type Request struct {
Method string // 请求方法
URL *url.URL // 请求地址
Proto string // 协议版本,"HTTP/1.0"
ProtoMajor int // 协议主版本号,“1”
ProtoMinor int // 协议主副版本号,“0”
Header Header // 请求头
Body io.ReadCloser // 请求的Body
ContentLength int64 // ContentLength记录相关内容的长度
TransferEncoding []string // TransferEncoding按从最外到最里的顺序列出传输编码
Close bool // Close在服务端指定是否在回复请求后关闭连接,在客户端指定是否在发送请求后关闭连接
Host string // Host指定URL会在其上寻找资源的主机
Form url.Values // Form是解析好的表单数据,包括URL字段的query参数和POST或PUT的表单数据
PostForm url.Values // PostForm是解析好的POST或PUT的表单数据
MultipartForm *multipart.Form // MultipartForm是解析好的多部件表单,包括上传的文件
Trailer Header // Trailer指定了会在请求主体之后发送的额外的头域
RemoteAddr string // RemoteAddr允许HTTP服务器和其他软件记录该请求的来源地址,一般用于日志
RequestURI string // RequestURI是被客户端发送到服务端的请求中未修改的URI
TLS *tls.ConnectionState // TLS字段允许HTTP服务器和其他软件记录接收到该请求的TLS连接的信息
}
对于Request,我们需要掌握的成员字段有Method设置请求方法,如果是需要使用GET方法就设置为“GET”。
URL字段为请求的地址,如:
http://www.baidu.com/
对于模拟客户端发起请求,我们经常需要设置请求头Header,HTTP规定头的键名(头名)是大小写敏感的,请求的解析器通过规范化请求头的键名来实现这一点。
如:
Accept-Encoding: gzip, deflate
Accept-Language: en-us
Connection: keep-alive
还有一个重要的成员为Form,Form是解析好的表单数据,包括URL字段的query参数和POST或PUT的表单数据,该字段只有在调用ParseForm后才有效。
如果需要模拟上传文件,则需要使用MultipartForm成员。
在客户端进行请求数据时,使用最多的请求方法为GET和POST,我们会针对这两个方法进行深入的学习。
- GET——从指定的资源请求数据。
- POST——向指定的资源提交要被处理的数据。
GET和POST是表单提交数据的两种基本方式。
- GET请求数据通过域名后缀url传送,用户可见,不安全;
- POST请求数据在请求报文正文里传输,相对比较安全。
GET用于请求指定的页面信息,并返回实体主体。它有如下特点:
- GET请求可被缓存。
- GET请求保留在浏览器历史记录中。
- GET请求可被收藏为书签。
- GET请求不应在处理敏感数据时使用。
- GET请求有长度限制。
- GET请求只应当用于取回数据。
一个最简单的GET请求示例如下,通过GET请求数据,并提交了两个参数key1和key2,多个参数之间使用符号“&”连接。
需要注意的是,在请求头结束后,也就是(Accept: /)下面,有一空行,这才是一个完整的HTTP请求头。
GET /index?key1=value1&key2=value2 HTTP/1.1
Host: localhost:8080
User-Agent: curl/7.55.1
Accept: */*
POST用于向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在请求体中。POST请求可能会导致新的资源的建立和(或)已有资源的修改。
POST提交数据有如下特点:
- POST请求不会被缓存。
- POST请求不会保留在浏览器历史记录中。
- POST不能被收藏为书签。
- POST请求对数据长度没有要求。
一个最简单的POST请求示例如下,与GET最大的不同之处在于,POST方法将请求的参数放到了请求的body中,而不是URL中。
POST /index HTTP/1.1
Host: localhost:8080
User-Agent: curl/7.55.1
Accept: */*
key1=value1&key2=value2
【提示】
对于GET方式的请求,浏览器会把HTTP header和data一并发送出去,服务器响应200并返回数据。
而对于POST,浏览器先发送header,服务器响应100 continue,浏览器再发送data,服务器再响应200并返回数据。当然也并不是所有浏览器都会在POST中发送两次包,如Firefox就只发送一次
Go语言中Client类型的GET和POST方法,在数据传输过程中分别对应了HTTP协议中的GET和POST方法。
二者主要区别如下:
- GET是用来从服务器上获得数据,而POST是用来向服务器传递数据。
- GET将表单中的数据按照variable=value的形式,添加到action所指向的URL后面,并且两者使用“?”连接,而各个变量之间使用“&”连接;POST是将表单中的数据放在form的数据体中,按照变量和值相对应的方式,传递到action所指向的URL。
- GET是不安全的,因为在传输过程中,数据被放在请求的URL中,而如今现有的很多服务器、代理服务器或者用户代理都会将请求URL记录到日志文件中,然后放在某个地方,这样就可能会有一些隐私的信息被第三方看到。另外,用户也可以在浏览器上直接看到提交的数据,一些系统内部消息将会一同显示在用户面前。而POST的所有操作对用户来说都是不可见的。
- GET传输的数据量小,这主要是因为受URL长度限制,而POST可以传输大量的数据,所以在上传文件时只能使用POST(当然还有一个原因,将在后面提到)。
- GET限制Form表单的数据集的值必须为ASCII字符,而POST支持整个ISO 10646字符集。
- 使用POST传输的数据,可以通过设置编码的方式正确转化中文,而GET传输的数据却没有变化。在以后的程序中,我们一定要注意这一点。
- POST会有浏览器提示重新提交表单的问题,GET则没有。