1. Client
- Client 结构体共有四个成员
- Transport 指定独立单次HTTP请求的机制
- CheckRedirect 指定处理重定向策略
- Jar 指定cookie管理器
- Timeout 指定文本类型的执行请求的时间限制
1
2
3
4
5
6
7
8
9
|
import "time"
type Client struct {
Transport RoundTripper
CheckRedirect func(req *Request, via []*Request)error
Jar CookieJar
Timeout time.Duration
}
|
- Client类型主要充当浏览器角色; 它拥有一下方法:
- Do get和post都是基于do方法进行的封装
- Head
- Get
- Post
- PostForm
1.1 启动client

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
|
/*
* @date: 2021/12/6
* @desc: ...
*/
package main
import (
"fmt"
"io/ioutil"
"net"
"net/http"
"time"
)
func main() {
// 创建连接池
transport := &http.Transport{
DialContext: (&net.Dialer{
Timeout: 30 * time.Second, // 连接超时
KeepAlive: 30 * time.Second, // 长连接保持时间
}).DialContext,
MaxIdleConns: 100, // 最大空闲连接
IdleConnTimeout: 90 * time.Second, //空闲超时时间
TLSHandshakeTimeout: 10 * time.Second, //tls 握手超时时间 (https使用)
ExpectContinueTimeout: 1 * time.Second, //100-continue状态码超时时间
}
// 创建客户端
client := http.Client{
Timeout: time.Second * 30, // 请求超时时间
Transport: transport,
}
// 请求数据
resp, err := client.Get("http://127.0.0.1:8080/bye")
if err != nil {
panic(err)
}
defer resp.Body.Close()
// 读取body内容
bds, err := ioutil.ReadAll(resp.Body)
if err != nil {
panic(err)
}
fmt.Println(string(bds))
}
|
2. Request
3. Get和Post的区别
- get是从服务器上获取数据, post是向服务器推送数据
- get和post传递参数的方式不同, get将参数放在url后面,post是将表单数据放在请求体中
- get数据不安全,用户提交的数据用户能看到, post对用户不可见;
- GET请求传输数据量很小, 而POST请求可以传输大量的数据
- POST传输数据可以通过设置编码的方式正确转化中文, 而GET请求传输的数据没有变化
3.1 发起GET请求
- 简单请求
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
package main
import (
"fmt"
"io"
"io/ioutil"
"net/http"
)
func main() {
get, err := http.Get("http://www.baidu.com")
if err != nil {
fmt.Println("get error", err)
return
}
defer func(Body io.ReadCloser) {
fmt.Println("close error")
err := Body.Close()
if err != nil {
}
}(get.Body)
all, err := ioutil.ReadAll(get.Body)
if err != nil {
fmt.Println("read error")
return
}
fmt.Println(string(all))
}
|
关于GET请求的参数需要使用Go语言内置的net/url
这个标准库来处理。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
func main() {
apiUrl := "http://127.0.0.1:9090/get"
// URL param
data := url.Values{}
data.Set("name", "小王子")
data.Set("age", "18")
u, err := url.ParseRequestURI(apiUrl)
if err != nil {
fmt.Printf("parse url requestUrl failed, err:%v\n", err)
}
u.RawQuery = data.Encode() // URL encode
fmt.Println(u.String())
resp, err := http.Get(u.String())
if err != nil {
fmt.Printf("post failed, err:%v\n", err)
return
}
defer resp.Body.Close()
b, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Printf("get resp failed, err:%v\n", err)
return
}
fmt.Println(string(b))
}
|
对应的Server端HandlerFunc如下:
1
2
3
4
5
6
7
8
|
func getHandler(w http.ResponseWriter, r *http.Request) {
defer r.Body.Close()
data := r.URL.Query()
fmt.Println(data.Get("name"))
fmt.Println(data.Get("age"))
answer := `{"status": "ok"}`
w.Write([]byte(answer))
}
|
- 自定义get 请求
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
package main
import (
"fmt"
"io/ioutil"
"net/http"
)
func main() {
client := &http.Client{}
request, err := http.NewRequest("GET", "http://www.baidu.com", nil)
if err != nil {
fmt.Println(err)
}
response, err := client.Do(request)
if err != nil {
fmt.Println(err)
}
fmt.Println(response.StatusCode) // 响应码
res, err := ioutil.ReadAll(response.Body)
fmt.Println(string(res)) // 获取的代码
}
|
3.2 发起Post请求
- 简单post请求
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
package main
import (
"fmt"
"io/ioutil"
"net/http"
"strings"
)
// net/http post demo
func main() {
url := "http://127.0.0.1:9090/post"
// 表单数据
//contentType := "application/x-www-form-urlencoded"
//data := "name=小王子&age=18"
// json
contentType := "application/json"
data := `{"name":"小王子","age":18}`
resp, err := http.Post(url, contentType, strings.NewReader(data))
if err != nil {
fmt.Printf("post failed, err:%v\n", err)
return
}
defer resp.Body.Close()
b, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Printf("get resp failed, err:%v\n", err)
return
}
fmt.Println(string(b))
}
|
对应的Server端HandlerFunc如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
func postHandler(w http.ResponseWriter, r *http.Request) {
defer r.Body.Close()
// 1. 请求类型是application/x-www-form-urlencoded时解析form数据
r.ParseForm()
fmt.Println(r.PostForm) // 打印form数据
fmt.Println(r.PostForm.Get("name"), r.PostForm.Get("age"))
// 2. 请求类型是application/json时从r.Body读取数据
b, err := ioutil.ReadAll(r.Body)
if err != nil {
fmt.Printf("read request.Body failed, err:%v\n", err)
return
}
fmt.Println(string(b))
answer := `{"status": "ok"}`
w.Write([]byte(answer))
}
|
- 自定义post请求
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
package main
import (
"fmt"
"io/ioutil"
"net/http"
"strings"
)
func main() {
resq, err:= http.Post("http://www.baidu.com",
"application/x-www-form-urlencoded",
strings.NewReader("user=admin&pass=admin"))
if err !=nil{
fmt.Println(err)
}
defer resq.Body.Close()
body, err:= ioutil.ReadAll(resq.Body)
if err!=nil{
fmt.Println(err)
}
fmt.Println(body)
}
|
4. curl工具
5. 启动server服务
-
方式一
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
package main
import (
"fmt"
"math/rand"
"net/http"
"time"
)
func indexHandler(w http.ResponseWriter, r *http.Request) {
rand.Seed(time.Now().UnixNano())
randNum := rand.Intn(2)
if randNum == 0 {
time.Sleep(5 * time.Second)
}
fmt.Fprintf(w, "quick response")
}
func main() {
http.HandleFunc("/", indexHandler)
err := http.ListenAndServe(":8000", nil)
if err != nil {
panic(err)
}
}
|
-
方式二:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
package main
import (
"log"
"net/http"
"time"
)
const ADDR = "127.0.0.1:8080"
func sayBay(w http.ResponseWriter, r *http.Request) {
time.Sleep(time.Second * 1)
_, err := w.Write([]byte("bye bye!"))
if err != nil {
return
}
}
func main() {
// 创建路由器
mux := http.NewServeMux()
// 设置路由规则
mux.HandleFunc("/bye", sayBay)
// 创建服务器
server := &http.Server{
Addr: ADDR,
WriteTimeout: time.Second * 3,
Handler: mux,
}
// 监听端口并提供服务
log.Println("starting http server at: " + ADDR)
log.Fatal(server.ListenAndServe())
}
|
常见错误码
- 200 成功状态吗
- 301 临时重定向
- 302 永久重定向
- 400 客户端 语法错误
- 401 客户端身份认证失败
- 403 拒绝访问
- 404 找不到资源
- 500 服务器内部错误
- 501 服务器不支持
- 502 错误的网关
- 503 服务器过载
- 504 网关超时
- 505 http协议错误