GoGET/POST请求教程展示了如何在Golang中发送HTTPGET和POST请求。
$ go version go version go1.18.1 linux/amd64
我们使用Go版本1.18。
HTTP
超文本传输协议(HTTP)是分布式协作超媒体信息系统的应用协议。HTTP协议是万维网数据通信的基础。
在代码示例中,我们使用免费提供的HTTP请求和响应服务httpbin.org
和微型HTML文件webcode.me
测试页面。
HTTP获取
HTTPGET方法请求指定资源的表示。使用GET的请求应该只检索数据。
HTTP发送
HTTPPOST方法向服务器发送数据。它通常在上传文件或提交完整的网络表单时使用。
去http
在Go中,我们使用http
包来创建GET和POST请求。该包提供HTTP客户端和服务器实现。
去GET请求
以下示例在Go中创建一个简单的GET请求。
package main import ( "fmt" "io/ioutil" "log" "net/http" ) func main() { resp, err := http.Get("http://webcode.me") if err != nil { log.Fatal(err) } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { log.Fatal(err) } fmt.Println(string(body)) }
我们向webcode.me
网页创建一个GET请求。
resp, err := http.Get("http://webcode.me")
使用Get
函数发出获取请求。
if err != nil { log.Fatal(err) }
我们检查错误。
defer resp.Body.Close()
客户端必须在完成后关闭响应主体。
body, err := ioutil.ReadAll(resp.Body)
我们使用ReadAll
读取正文的内容。
fmt.Println(string(body))
我们将接收到的数据打印到控制台。
$ go run get_req.go <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>My html page</title> </head> <body> <p> Today is a beautiful day. We go swimming and fishing. </p> <p> Hello there. How are you? </p> </body> </html>
我们可以使用io.Copy
函数代替ioutil.ReadAll
。
package main import ( "io" "log" "net/http" "os" ) func main() { resp, err := http.Get("http://webcode.me") if err != nil { log.Fatal(err) } defer resp.Body.Close() _, err = io.Copy(os.Stdout, resp.Body) if err != nil { log.Fatal(err) } }
io.Copy
函数从源复制到目标,直到在源上达到EOF或发生错误。它返回复制的字节数和复制时遇到的第一个错误(如果有)。
在下一个示例中,页面被写入文件。
package main import ( "log" "net/http" "os" ) func main() { r, err := http.Get("http://webcode.me") if err != nil { log.Fatal(err) } defer r.Body.Close() f, err := os.Create("index.html") if err != nil { log.Fatal(err) } defer f.Close() _, err = f.ReadFrom(r.Body) if err != nil { log.Fatal(err) } }
我们使用os.Create
创建一个新文件,并使用ReadFrom
将内容写入文件。
去异步请求
Go有用于发出异步请求的goroutines。goroutine是由Go运行时管理的轻量级线程。
package main import ( "fmt" "io/ioutil" "log" "net/http" "regexp" "sync" ) func main() { urls := []string{ "http://webcode.me", "https://example.com", "http://httpbin.org", "https://www.perl.org", "https://www.php.net", "https://www.python.org", "https://code.visualstudio.com", "https://clojure.org", } var wg sync.WaitGroup for _, u := range urls { wg.Add(1) go func(url string) { defer wg.Done() content := doReq(url) title := getTitle(content) fmt.Println(title) }(u) } wg.Wait() } func doReq(url string) (content string) { resp, err := http.Get(url) defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { log.Fatal(err) } return string(body) } func getTitle(content string) (title string) { re := regexp.MustCompile("<title>(.*)</title>") parts := re.FindStringSubmatch(content) if len(parts) > 0 { return parts[1] } else { return "no title" } }
我们发出多个异步HTTP请求。我们获取每个网页的title
标签的内容。
var wg sync.WaitGroup
WaitGroups
用于管理goroutine。它等待一组goroutines完成
go func(url string) { defer wg.Done() content := doReq(url) title := getTitle(content) fmt.Println(title) }(u)
goroutine是使用go
关键字创建的。
$ go run async_req.go The Perl Programming Language - www.perl.org Welcome to Python.org Visual Studio Code - Code Editing. Redefined PHP: Hypertext Preprocessor Example Domain httpbin.org Clojure My html page
使用查询参数进行GET请求
以下示例将查询参数附加到URL。
package main import ( "fmt" "io/ioutil" "log" "net/http" "net/url" ) func main() { name := "John Doe" occupation := "gardener" params := "name=" + url.QueryEscape(name) + "&" + "occupation=" + url.QueryEscape(occupation) path := fmt.Sprintf("https://httpbin.org/get?%s", params) resp, err := http.Get(path) if err != nil { log.Fatal(err) } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { log.Fatal(err) } fmt.Println(string(body)) }
查询参数的值使用url.QueryEscape
进行转义。
$ go run get_req_params.go { "args": { "name": "John Doe", "occupation": "gardener" }, "headers": { "Accept-Encoding": "gzip", "Host": "httpbin.org", "User-Agent": "Go-http-client/2.0", "X-Amzn-Trace-Id": "Root=1-6000718d-443f64a345d2252d39b49b8d" }, ... "url": "https://httpbin.org/get?name=John+Doe&occupation=gardener" }
去HTTPPOST请求FORM数据
PostForm
向指定的URL发出POST,数据的键和值经过URL编码作为请求主体。Content-Type标头设置为application/x-www-form-urlencoded。数据在请求的正文中发送;键和值被编码在由“&”分隔的键值元组中,键和值之间有一个“=”。
package main import ( "encoding/json" "fmt" "log" "net/http" "net/url" ) func main() { data := url.Values{ "name": {"John Doe"}, "occupation": {"gardener"}, } resp, err := http.PostForm("https://httpbin.org/post", data) if err != nil { log.Fatal(err) } var res map[string]interface{} json.NewDecoder(resp.Body).Decode(&res) fmt.Println(res["form"]) }
我们向https://httpbin.org/post
页面发送POST请求。
resp, err := http.PostForm("https://httpbin.org/post", data)
数据通过PostForm
函数发送。
var res map[string]interface{} json.NewDecoder(resp.Body).Decode(&res)
我们将响应主体解码为地图。
fmt.Println(res["form"])
我们打印接收到的数据。
$ go run post_req_form.go map[name:John Doe occupation:gardener]
去HTTPPOST请求JSON数据
以下示例发送带有JSON格式数据的POST请求。
package main import ( "bytes" "encoding/json" "fmt" "log" "net/http" ) func main() { values := map[string]string{"name": "John Doe", "occupation": "gardener"} json_data, err := json.Marshal(values) if err != nil { log.Fatal(err) } resp, err := http.Post("https://httpbin.org/post", "application/json", bytes.NewBuffer(json_data)) if err != nil { log.Fatal(err) } var res map[string]interface{} json.NewDecoder(resp.Body).Decode(&res) fmt.Println(res["json"]) }
我们向httpbin.org/post
网页生成一个POST请求。post数据是从地图中获取的,并通过encoding/json
包转换为字符串。
values := map[string]string{"name": "John Doe", "occupation": "gardener"} json_data, err := json.Marshal(values)
使用json.Marshal
将地图序列化为JSON字符串。
resp, err := http.Post("https://httpbin.org/post", "application/json", bytes.NewBuffer(json_data))
当我们发布数据时,我们将内容类型设置为application/json
。
$ go run post_req_json.go map[name:John Doe occupation:gardener]
在本教程中,我们在Go中创建了GET和POST请求。
列出所有Go教程。