Go语言学习#8-如何发送HTTP请求


=Start=

缘由:

学习和整理一下如何使用Go 语言发送HTTP请求,方便以后使用和参考。

正文:

参考解答:

首先看一下 net/http 包中和GET/POST函数相关的方法和结构体说明:

func Get(url string) (resp *Response, err error)

func Post(url, contentType string, body io.Reader) (resp *Response, err error)

func PostForm(url string, data url.Values) (resp *Response, err error)

// 对于POST请求的内容字段/参数,需要是 io.Reader 类型,而常规的几种方式有:
strings.NewReader("name=hi")
url.Values{"key": {"Value"}, "id": {"123"}})
bytes.NewBuffer([]byte(`{"title":"a breakfast"}`))
// 是因为它们均实现了 io.Reader 接口,所以可以使用

func NewRequest(method, url string, body io.Reader) (*Request, error)

func (c *Client) Do(req *Request) (*Response, error)
// To make a request with custom headers, use NewRequest and Client.Do.
// 如果你想自定义header字段的话,请使用 NewRequest 函数结合 Client.Do 方法。
`

然后再结合几个可实际运行的例子方便理解和验证:

package main

import (
    "bytes"
    "io/ioutil"
    "log"
    "net/http"
    "net/url"
    "strings"
)

var (
    url_str  = "http://myexternalip.com/raw"
    url_post = "https://httpbin.org/post"
)

// 对指定URL发起GET请求,并以string格式返回response
func httpGet(url string) string {
    resp, err := http.Get(url)
    if err != nil {
        // handle error
        log.Printf("http.Get(%s) Error:[%v]\n", url, err)
    }
    defer resp.Body.Close() // 使用defer函数进行响应体的自动close

    body, err := ioutil.ReadAll(resp.Body) // 返回的body是 []byte 类型
    if err != nil {
        // handle error
        log.Printf("http.Get(%s) Error:[%v]\n", url, err)
    }

    return string(body) // 直接用 string 方法将 []byte 类型转换成 string 类型字符串
}

// 对指定URL发起POST请求(用编码好的字符串格式模拟表单提交),并以string格式返回response
func httpPost(url string) string {
    resp, err := http.Post(url,
        "application/x-www-form-urlencoded",
        strings.NewReader("name=hi&age=20"))
    if err != nil {
        log.Printf("http.Post(%s) Error:[%v]\n", url, err)
    }
    defer resp.Body.Close()

    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        // handle error
        log.Printf("http.Post(%s) Error:[%v]\n", url, err)
    }

    return string(body)
}

// 对指定URL发起POST请求(用类似kv的形式填充表单提交的内容),并以string格式返回response
func httpPostForm(url_str string) string {
    v := url.Values{}
    v.Set("username", "xxxx")
    v.Set("password", "xxxx")

    resp, err := http.PostForm(url_str,
        v)
    // url.Values{"key": {"Value"}, "id": {"123"}})
    if err != nil {
        // handle error
        log.Printf("http.PostForm(%s) Error:[%v]\n", url_str, err)
    }
    defer resp.Body.Close()

    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        // handle error
        log.Printf("http.PostForm(%s) Error:[%v]\n", url_str, err)
    }

    return string(body)
}

// 用http.NewRequest+client.Do的方式发起可以自定义header的POST请求(表单提交格式)
func httpDo(url string) string {
    client := &http.Client{}

    req, err := http.NewRequest("POST", url, strings.NewReader("name=hi"))
    if err != nil {
        // handle error
        log.Printf("httpDo(%s) Error:[%v]\n", url, err)
    }
    req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
    req.Header.Set("Cookie", "name=anyone")

    resp, err := client.Do(req)
    defer resp.Body.Close()

    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        // handle error
        log.Printf("httpDo(%s) Error:[%v]\n", url, err)
    }

    return string(body)
}

// 用http.NewRequest+client.Do的方式发起可以自定义header的POST请求(json格式)
func httpDoJson(url string) string {
    client := &http.Client{}

    jsonStr := []byte(`{"title":"a breakfast"}`)
    req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonStr))
    if err != nil {
        // handle error
        log.Printf("httpDo(%s) Error:[%v]\n", url, err)
    }
    req.Header.Set("Content-Type", "application/json")
    req.Header.Set("Cookie", "id=anyone")
    req.Header.Set("User-Agent", "iPhone X")

    resp, err := client.Do(req)
    defer resp.Body.Close()

    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        // handle error
        log.Printf("httpDo(%s) Error:[%v]\n", url, err)
    }

    return string(body)
}

func main() {
    body := httpGet(url_str)
    log.Printf("httpGet(%s): '%s'\n\n", url_str, strings.Replace(body, "\n", "", -1))

    body = httpPost(url_post)
    log.Printf("httpPost(%s): '%s'\n\n", url_post, body)

    body = httpPostForm(url_post)
    log.Printf("httpPostForm(%s): '%s'\n\n", url_post, body)

    body = httpDo(url_post)
    log.Printf("httpDo(%s): '%s'\n\n", url_post, body)

    body = httpDoJson(url_post)
    log.Printf("httpDoJson(%s): '%s'\n\n", url_post, body)
}

&

2018/10/26 23:59:25 httpDoJson(https://httpbin.org/post): '{
  "args": {},
  "data": "{\"title\":\"a breakfast\"}",
  "files": {},
  "form": {},
  "headers": {
    "Accept-Encoding": "gzip",
    "Connection": "close",
    "Content-Length": "23",
    "Content-Type": "application/json",
    "Cookie": "id=anyone",
    "Host": "httpbin.org",
    "User-Agent": "iPhone X"
  },
  "json": {
    "title": "a breakfast"
  },
  "origin": "216.22.34.83",
  "url": "https://httpbin.org/post"
}
'

 

tips: 这里借助网站 https://httpbin.org/post (可以把每次我们的请求header和body回显出来)方便我们验证header等字段的修改是否生效,非常好用。

 

参考链接:

=END=

, ,

《 “Go语言学习#8-如何发送HTTP请求” 》 有 5 条评论

  1. Go 语言中的Web爬取
    https://www.devdungeon.com/content/web-scraping-go
    `
    导语
    Web 爬虫的道德和伦理
    先决条件(Golang + goquery)
    发起一个 HTTP GET 请求
    发起一个 HTTP GET 请求(带有超时控制)
    自定义 HTTP 请求header
    下载一个 URL 链接
    使用 字符串匹配 查找页面标题
    使用 正则表达式 查找HTML注释
    使用 goquery 查找页面上的所有链接
    解析 URL
    使用 goquery 查找页面上的所有图片
    发起一个 HTTP POST 请求
    发起一个带有 cookie 的 HTTP 请求
    如何登录网站
    Web 爬取
    `

  2. 用Golang写爬虫(八) – 使用GORM存入MySQL数据库
    https://strconv.com/posts/use-gorm/
    用Golang写爬虫(七) – 如何保存数据到文件
    https://strconv.com/posts/save-to-file/
    用Golang写爬虫(六) – 使用colly
    https://strconv.com/posts/use-colly/
    用Golang写爬虫(五) – 使用XPath
    https://strconv.com/posts/web-crawler-exercise-5/
    用Golang写爬虫(四) – 使用soup
    https://strconv.com/posts/web-crawler-exercise-4/
    用Golang写爬虫(三) – 使用goquery
    https://strconv.com/posts/web-crawler-exercise-3/
    用Golang写爬虫(二) – 并发
    https://strconv.com/posts/web-crawler-exercise-2/
    用Golang写爬虫(一)
    https://strconv.com/posts/web-crawler-exercise-1/
    https://github.com/golang-dev/strconv.code/blob/master/goquery/doubanCrawler.go

回复 hi 取消回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注