=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 条评论
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 爬取
`
Go 语言中如何发起Tor HTTP请求
https://www.devdungeon.com/content/making-tor-http-requests-go
https://godoc.org/golang.org/x/net/proxy
https://gist.github.com/Yawning/bac58e08a05fc378a8cc
如何查看你通过curl或是其它方法发送的GET/POST请求内容和对应的返回数据呢? (display debug curl get post body data)
https://superuser.com/questions/291424/how-do-you-display-post-data-with-curl/1129975#1129975
https://httpbin.org/#/HTTP_Methods/post_post
用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
goquery 文档
https://www.cnblogs.com/diegodu/p/5761961.html
https://www.itlipeng.cn/2017/04/25/goquery-%E6%96%87%E6%A1%A3/
https://godoc.org/github.com/PuerkitoBio/goquery
zhihu-go 源码解析:用 goquery 解析 HTML
http://liyangliang.me/posts/2016/03/zhihu-go-insight-parsing-html-with-goquery/