Golang中常用的标准库之http

网络编程中绕不过去的一个板块就是http服务,无论是老架构上还是微服务架构上,客户端服务端、服务端直接通信几乎都是以httpRPC通信为主,这里先记录Golang中的http库以及常用的Gin框架。

http

服务端

1
2
3
4
5
6
7
8
9
func HelloServer(w http.ResponseWriter, r *http.Request) {
io.WriteString(w, "hello world")
return
}

func server() {
http.HandleFunc("/", HelloServer)
log.Fatal(http.ListenAndServe(":8080", nil))
}

客户端

客户端调用方式

1
2
3
response, _ := http.Get("https://www.baidu.com")
// 源码看,其实上面这种就是下面
response, _ := http.DefaultClient.Get("https://www.baidu.com")

httpresponse返回的是一个http.Response,解析的方式一般有两种

1
2
response, _ := http.DefaultClient.Get("https://www.baidu.com")
defer response.Body.Close()

只获取body

1
ioutil.ReadAll(response.Body)

解析response

1
dumpResponse, _ := httputil.DumpResponse(response, true)

通过client控制header

1
2
3
4
client := http.DefaultClient
request, err := http.NewRequest(http.MethodGet, "https://www.baidu.com", nil)
request.Header.Add("User-Agent", "test") // Header增加内容
response, err := client.Do(request)

查看转发

1
2
3
4
5
6
7
8
client := http.Client{
CheckRedirect: func(req *http.Request, via []*http.Request) error {
fmt.Println("req: ", req) // 打印请求的信息,如果有转发,会打印转发的信息
return nil
},
}
request, err := http.NewRequest(http.MethodGet, "http://www.baidu.com/", nil)
response, err := client.Do(request)

性能分析

启动http监听时,加上pprof

1
_ "net/http/pprof"

打开对应页面即可

1
http://127.0.0.1:8080/debug/pprof/

image-20220703210153758

使用go tool 获取30s的CPU的使用率

1
go tool pprof http://127.0.0.1:8080/debug/pprof/profile 

内存

1
go tool pprof http://localhost:6060/debug/pprof/heap

具体获取的内容可以查看源码说明文档或者指导文档

https://go.dev/blog/pprof

json格式

将结构体序列化成json字符串,json中的key可以通过tag指定。omitempty当结构体中的值为零值,则该字段不序列化。

1
2
3
4
5
6
type User struct {
ID int `json:"id"`
Name string `json:"name"`
Age int `json:"age,omitempty"`
Books []Book `json:"books"`
}

反序列化

方式一:通过相同的结构体反序列化

1
err := json.Unmarshal([]byte(res), &m) // 传入地址

方式二:通过map[string]interface{}以及类型断言

1
2
3
m := make(map[string]interface{}) 
// 先反序列成map[string]interface,然后类型断言interface是[]interface,获取角标之后,再类型断言成map[string]interface
fmt.Println(m["books"].([]interface{})[1].(map[string]interface{})["name"])

gin

比较常用的第三方http库,提供contextmidware能力

1
2
3
4
5
6
7
r := gin.Default()
r.GET("/ping", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "pong",
})
})
r.Run(":8080")

midware

1
2
3
4
5
6
7
8
9
10
r.Use(func(c *gin.Context) {
requestID := rand.Int()
c.Set("requestID", requestID)
s := time.Now()
// path
logger.Info("incoming request", zap.String("path", c.Request.URL.String()))
c.Next() // c.Next()上面的是接受到请求就可以处理;c.Next()下面的是请求处理完之后运行的逻辑。
// response code
logger.Info("message", zap.Int("code", c.Writer.Status()), zap.Duration("elapsed", time.Now().Sub(s)))
})

context

1
2
3
4
5
6
7
// 在midware中的context设置key value
requestID := rand.Int()
c.Set("requestID", requestID)
// 在handler中通过context获取key value
if requestID, exists := c.Get("requestID"); exists {
res["requestID"] = requestID
}