有時(shí)候我們需要統(tǒng)計(jì)web service接口的數(shù)據(jù),比如記錄日志、統(tǒng)計(jì)API調(diào)用時(shí)間币狠、或者對(duì)HandleFunc進(jìn)行錯(cuò)誤處理,
這個(gè)時(shí)候砾层,middleware就很有幫助漩绵。
最初版本
我們目前有個(gè)程序,監(jiān)聽8080端口肛炮,提供兩個(gè)接口止吐,
1. compute:進(jìn)行計(jì)算,耗時(shí)在500ms-1000ms之間
2. version:得到版本號(hào)侨糟,耗時(shí)在10ms-60ms之間
package main
import (
"log"
"math/rand"
"net/http"
"time"
)
// Compute is compute process for doing task
func Compute(w http.ResponseWriter, r *http.Request) {
time.Sleep(time.Duration((500 + rand.Intn(500))) * time.Millisecond)
}
// Version is getting version task
func Version(w http.ResponseWriter, r *http.Request) {
time.Sleep(time.Duration((10 + rand.Intn(50))) * time.Millisecond)
w.Write([]byte("version"))
}
func main() {
http.HandleFunc("/compute", Compute)
http.HandleFunc("/version", Version)
log.Panic(http.ListenAndServe(":8080", nil))
}
調(diào)用結(jié)果如下碍扔,
# curl http://localhost:8080/compute
finish
增加日志
需要記錄每次調(diào)用接口的名字。
有兩種方式記錄日志秕重,
1. 在每一個(gè)HandleFunc第一行輸出URI
2. 增加中間件封裝HandleFunc
對(duì)于第一種情況不同,修改Compute()函數(shù)為,
// Compute is compute process for doing task
func Compute(w http.ResponseWriter, r *http.Request) {
log.Printf(r.RequestURI)
time.Sleep(time.Duration((500 + rand.Intn(500))) * time.Millisecond)
w.Write([]byte("finish"))
}
運(yùn)行得到結(jié)果為溶耘,
2017/12/11 23:07:24 /compute
對(duì)于API少的情況二拐,還比較適用。但是對(duì)于API接口比較多的情況凳兵,修改每一個(gè)函數(shù)就不太合適百新。并且當(dāng)我們不光想統(tǒng)計(jì)URI信息時(shí),還需要統(tǒng)計(jì)每一個(gè)調(diào)用接口的其他信息時(shí)庐扫,就需要修改每一處HandleFunc饭望。
所以我們可以使用Middleware
形式來完成。
我們希望使用middlware以后聚蝶,對(duì)于main()函數(shù)變?yōu)椋?/p>
func main() {
http.HandleFunc("/compute", middleware(Compute))
http.HandleFunc("/version", middleware(Version))
log.Panic(http.ListenAndServe(":8080", nil))
}
使用middlware對(duì)每一個(gè)http handle func進(jìn)行封裝杰妓,在middleware中進(jìn)行相應(yīng)的需求處理,比如日志記錄碘勉、錯(cuò)誤處理、用時(shí)統(tǒng)計(jì)等桩卵。
func middleware(fn func(w http.ResponseWriter, r *http.Request)) func(w http.ResponseWriter, r *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
begin := time.Now()
defer func() {
log.Printf("[%s] %s, time_used: %v", r.Method, r.URL.String(), time.Now().Sub(begin))
}()
fn(w, r)
}
}
middlware
入?yún)⒑头祷刂刀紴?code>func(w http.ResponseWriter, r *http.Request)類型验靡。
在middleware
中,進(jìn)行了調(diào)用接口URI的統(tǒng)計(jì)和用時(shí)統(tǒng)計(jì)雏节。
完整的代碼如下胜嗓,
package main
import (
"log"
"math/rand"
"net/http"
"time"
)
// Compute is compute process for doing task
func Compute(w http.ResponseWriter, r *http.Request) {
time.Sleep(time.Duration((500 + rand.Intn(500))) * time.Millisecond)
w.Write([]byte("finish"))
}
// Version is getting version task
func Version(w http.ResponseWriter, r *http.Request) {
time.Sleep(time.Duration((10 + rand.Intn(50))) * time.Millisecond)
w.Write([]byte("version"))
}
func middleware(fn func(w http.ResponseWriter, r *http.Request)) func(w http.ResponseWriter, r *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
begin := time.Now()
defer func() {
log.Printf("[%s] %s, time_used: %v", r.Method, r.URL.String(), time.Now().Sub(begin))
}()
fn(w, r)
}
}
func main() {
http.HandleFunc("/compute", middleware(Compute))
http.HandleFunc("/version", middleware(Version))
log.Panic(http.ListenAndServe(":8080", nil))
}
測(cè)試
curl http://localhost:8080/compute
# 2017/12/13 16:57:15 [GET] /compute, time_used: 583.357048ms
curl http://localhost:8080/version
# 2017/12/13 16:57:24 [GET] /version, time_used: 47.09209ms