超文本传输协议(Hypertext Transfer Protocol,HTTP)
理解HTTP
要理解HTTP请求的结构,一种不错的方式是使用curl。输入命令行如下:
curl -s -o /dev/null -v http://google.com
运行结果如下:
* Trying 172.217.160.78:80...
* Connected to google.com (172.217.160.78) port 80 (#0)
> GET / HTTP/1.1
> Host: google.com
> User-Agent: curl/7.77.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 301 Moved Permanently
< Location: http://www.google.com/
< Content-Type: text/html; charset=UTF-8
< Date: Wed, 26 Jan 2022 12:07:41 GMT
< Expires: Fri, 25 Feb 2022 12:07:41 GMT
< Cache-Control: public, max-age=2592000
< Server: gws
< Content-Length: 219
< X-XSS-Protection: 0
< X-Frame-Options: SAMEORIGIN
<
{ [219 bytes data]
* Connection #0 to host google.com left intact
在verbose模式下的curl描述服务器和客户端之间传输的多个请求响应。其中的日志详细说明了发出的请求和收到的响应,对其解读如下。
以字符>打头的行描述了客户端发出的请求。
以字符<打头的行描述收到的响应。
请求的详细信息描述了随请求发送的一些报头,这些报头向服务器提供了一些有关客户端的信息。
响应详细描述了一些报头,这些报头指出了响应的内容类型、长度和发送时间。
发出GET请求
Go语言在net/http包中提供了一个快捷方式,可用于发出简单的GET请求。
GET请求,程序清单如下:
package main
import (
"fmt"
"io/ioutil"
"log"
"net/http"
)
func main() {
response, err := http.Get("https://ifconfig.io")
if err != nil {
log.Fatal(err)
}
defer response.Body.Close()
body, err := ioutil.ReadAll(response.Body)
if err != nil {
log.Fatal(err)
}
fmt.Printf("%s", body)
}
运行结果如下:
39.187.125.38
发出POST请求
POST请求,程序清单如下:
package main
import (
"fmt"
"io/ioutil"
"log"
"net/http"
"strings"
)
func main() {
postData:=strings.NewReader(`{"some":"json"}`)
response, err:=http.Post("https://httpbin.org/post","application/json",postData)
if err!=nil{
log.Fatal(err)
}
defer response.Body.Close()
body, err := ioutil.ReadAll(response.Body)
if err != nil {
log.Fatal(err)
}
fmt.Printf("%s", body)
}
运行结果如下:
{
"args": {},
"data": "{\"some\":\"json\"}",
"files": {},
"form": {},
"headers": {
"Accept-Encoding": "gzip",
"Content-Length": "15",
"Content-Type": "application/json",
"Host": "httpbin.org",
"User-Agent": "Go-http-client/2.0",
"X-Amzn-Trace-Id": "Root=1-61f13d73-0184660a5ffb645c019256f7"
},
"json": {
"some": "json"
},
"origin": "39.187.125.38",
"url": "https://httpbin.org/post"
}
进一步控制HTTP请求
使用自定义客户端,程序清单如下:
package main
import (
"fmt"
"io/ioutil"
"log"
"net/http"
)
func main() {
client := &http.Client{}
request, err := http.NewRequest("GET", "https://ifconfig.co", nil)
if err != nil {
log.Fatal(err)
}
response, err := client.Do(request)
defer response.Body.Close()
body, err := ioutil.ReadAll(response.Body)
if err != nil {
log.Fatal(err)
}
fmt.Printf("%s", body)
}
运行结果如下:
39.185.200.242
调试HTTP请求
调试请求,程序清单如下:
package main
import (
"fmt"
"io/ioutil"
"log"
"net/http"
"net/http/httputil"
"os"
)
func main() {
debug := os.Getenv("DEBUG")
client := &http.Client{}
request, err := http.NewRequest("GET", "http://ifconfig.co", nil)
if err != nil {
log.Fatal(err)
}
if debug == "1" {
debugRequest, err := httputil.DumpRequestOut(request, true)
if err != nil {
log.Fatal(err)
}
fmt.Printf("%s", debugRequest)
}
response, err := client.Do(request)
defer response.Body.Close()
if debug == "1" {
debugResponse, err := httputil.DumpResponse(response, true)
if err != nil {
log.Fatal(err)
}
fmt.Printf("%s", debugResponse)
}
body, err := ioutil.ReadAll(response.Body)
if err != nil {
log.Fatal(err)
}
fmt.Printf("%s\n", body)
}
运行结果如下:
39.185.200.242
输入命令行如下:
DEBUG=1 go run main.go
如windows环境下,输入两行命令行,分别是“set DEBUG=1”和“go run main.go”
运行结果如下:
GET / HTTP/1.1
Host: ifconfig.co
User-Agent: Go-http-client/1.1
Accept-Encoding: gzip
HTTP/1.1 200 OK
Content-Length: 15
Alt-Svc: h3=":443"; ma=86400, h3-29=":443"; ma=86400
Cf-Cache-Status: DYNAMIC
Cf-Ray: 6d830912ef3713d8-SEA
Connection: keep-alive
Content-Type: text/plain; charset=utf-8
Date: Fri, 04 Feb 2022 09:57:33 GMT
Nel: {"success_fraction":0,"report_to":"cf-nel","max_age":604800}
Report-To: {"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v3?s=jQxqcAb03W4fzDSRbyYDDT4ne%2F2U6UO6NF9DS39Zi01V6jRTkfE%2Fd1%2B85TeOq5%2B%2BsGcFLooqenMN2%2BPARV612f6XqmU0c7H4vLtlHZijifP3822qQBCCDdFaqWjzuw%3D%3D"}],"group":"cf-nel","max_age":604800}
Server: cloudflare
39.185.200.242
39.185.200.242
要请求JSON数据,可修改客户端,设置一个请求JSON的报头。如下:
request.Header.Add("Accept","application/json")
处理超时