Golang HTTP GET/POST 请求

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

赞(0) 打赏

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏