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教程。
