非零基础自学Golang
文章目录
- 非零基础自学Golang
- 第17章 HTTP编程(上)
- 17.2 HTTP客户端
- 17.2.4 发起POST请求
第17章 HTTP编程(上)
17.2 HTTP客户端
17.2.4 发起POST请求
在上一小节我们使用了http.NewRequest来创建一个请求,http.NewRequest有三个参数,第一个是请求方法Method,第二个是请求地址URL,最后一个参数是body,其类型为io.Reader。
GET方法不需要使用body参数,只需传入nil即可,如果是POST请求,则需要使用该参数。
如果body参数实现了io.Closer接口,Request返回值的Body字段会被设置为body,并会被Client类型的Do、Post和PostForm方法以及Transport.RoundTrip方法关闭。
举个例子:
[ 动手写 17.2.6]
package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
client := &http.Client{}
// 使用NopCloser 创建一个实现io.Closer 接口的body
body := io.NopCloser(strings.NewReader("user=admin&pass=admin"))
req, err := http.NewRequest("POST", "http://www.baidu.com", body)
if err != nil {
fmt.Println(err)
}
// 打印输出 body
req_body, err := io.ReadAll(req.Body)
fmt.Println(string(req_body))
// POST 提交表单需要添加此 Header 头
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
resp, err := client.Do(req)
if err != nil {
fmt.Println(err)
}
// 在client 使用Do 方法后, 再次打印Body 发现Body 已经被关闭, 使用ReadAll 读取会导致错误
req_body, err = io.ReadAll(resp.Request.Body)
if err != nil {
fmt.Println(err)
}
fmt.Println(string(req_body))
}
动手写17.2.6使用了ioutil.NopCloser创建了一个实现io.Closer接口的body对象,将其传入http.NewRequest的第三个参数,在发起请求前(client.Do()前),打印输出了req.Body。
在请求后再次以同样的方式打印输出请求Body就会发现程序报错,原因是请求的Body在Client类型的Do方法运行后就会被关闭,程序输出空指针异常。
运行结果如下:
我们同样可以使用http包封装后的POST方法来实现POST请求。
func Post(url string, bodyType string, body io.Reader) (resp *Response, err error)
Post向指定的URL发出一个POST请求,bodyType为POST数据的类型,body为POST数据,作为请求的主体。如果参数body实现了io.Closer接口,它会在发送请求后被关闭,调用者有责任在读取完返回值resp的主体后关闭它。
该方法是对Client的POST方法的包装。
[ 动手写 17.2.7]
package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
resp, err := http.Post("http://www.baidu.com", "application/x-www-form-urlencoded", strings.NewReader("user=admin&pass=admin"))
if err != nil {
fmt.Println(err)
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
fmt.Println(err)
}
fmt.Println(string(body))
}
运行结果
除了POST方法,http包还封装了一个叫PostForm的方法。
func PostForm(url string, data url.Values) (resp *Response, err error)
PostForm向指定的URL发出一个POST请求,url.Values类型的data会被编码为请求的主体。如果返回值err为nil,resp.Body总是非nil的,调用者应该在读取完resp.Body后关闭它。该方法是对Client的PostForm方法的包装。
我们使用PostForm来改写动手写17.2.7:
[ 动手写 17.2.8]
package main
import (
"fmt"
"io"
"net/http"
"net/url"
)
func main() {
resp, err := http.PostForm("http://www.baidu.com", url.Values{"user": {"admin"}, "pass": {"admin"}})
if err != nil {
fmt.Println(err)
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
fmt.Println(err)
}
fmt.Println(string(body))
}
运行结果
OK,运行效果一致。