Go的中間件

中間件

中間件這個東西其實指的很多,比如消息隊列。可以說但凡是在業務邏輯之前的,都可以被說是中間件。比如鑑權,日誌這些。go語言裏面對中間件的使用比較有意思。先看一個簡單的邏輯:

一個簡單的http請求

package main

import (
	"log"
	"net/http"
)

func hello(wr http.ResponseWriter,r *http.Request){
	status,err:=wr.Write([]byte("hello,world"))
	if err!=nil{
		log.Print("write fail:%v",err)
	}else{
		log.Println("success: ",status)
	}
}
func main(){
	http.HandleFunc("/hello",hello)
	err:=http.ListenAndServe(":9999",nil)
	if err!=nil{
		log.Println("hand fail:%v",err)
	}
}

這是個很簡單的http請求,這個請求掛載了一個hello服務。簡單的調用一下:
在這裏插入圖片描述
現在如果說要計算這個函數的耗時,那麼可以加點這樣的邏輯:

package main

import (
	"log"
	"net/http"
	"os"
	"time"
)
var logger = log.New(os.Stdout, "", 0)
func hello(wr http.ResponseWriter,r *http.Request){
	timeStart:=time.Now()
	status,err:=wr.Write([]byte("hello,world"))
	if err!=nil{
		log.Print("write fail:%v",err)
	}else{
		log.Println("success: ",status)
	}
	timeElapsed:=time.Since(timeStart)
	logger.Println(timeElapsed)
}
func main(){
	http.HandleFunc("/hello",hello)
	err:=http.ListenAndServe(":9999",nil)
	if err!=nil{
		log.Println("hand fail:%v",err)
	}
}

請求一下可以看到日誌:
在這裏插入圖片描述

存在的問題

其實很明顯,新加的功能其實是修改了代碼,這個是不符合程序設計的開閉原則。但是現在也不是oop?你給我講OC原則?emmm,確實,但是如果這樣的函數有很多,每個都加一下,其實也是不小的工作量,更難受的是容易漏掉。如果在java裏面,我們可以用aop織如一個切面,來完成這個功能,那麼在go裏面呢?

問題所在

其實開發中,很多這樣的問題。這些功能其實和業務不相關,但是這些信息需要統計。比如日誌功能,服務滲透率統計,鑑權這些。其實這些東西和業務不是很相關,這裏可以用中間件來剝離這些非業務邏輯,來完成功能的拓展。思考了java的aop實現,其實就是一種動態代理,核心要點就是使用了代理模式,所以可以參考這個邏輯,設計go語言裏面的代理邏輯。

問題解決

package main

import (
	"log"
	"net/http"
	"os"
	"time"
)
var logger = log.New(os.Stdout, "", 0)
func hello(wr http.ResponseWriter,r *http.Request){
	status,err:=wr.Write([]byte("hello,world"))
	if err!=nil{
		log.Print("write fail:%v",err)
	}else{
		log.Println("success: ",status)
	}

}
func timeMiddleware(next http.HandlerFunc)http.Handler{
	return http.HandlerFunc(func(wr http.ResponseWriter, r *http.Request) {
		timeStart:=time.Now()
		// 業務邏輯
		next.ServeHTTP(wr,r)

		timeElapsed:=time.Since(timeStart)
		logger.Println(timeElapsed)
	})
}
func main(){
	http.Handle("/hello",timeMiddleware(hello))
	err:=http.ListenAndServe(":9999",nil)
	if err!=nil{
		log.Println("hand fail:%v",err)
	}
}

可以看到,這種模式就是可以很好地剝離出業務邏輯。但是這種寫法並不是很優雅。其實可以看到,其實中間件就是一個函數,返回了一個處理函數,這個函數可以被說是代理函數。下面用gin框架怎麼使用中間件爲例,說明真實的開發中,是怎麼使middleware的。

gin中的middleware

首先,gin中的middleware返回的處理函數類型是固定的,都是:gin.HandlerFunc.
首先定義兩個中間件:
在這裏插入圖片描述定義好以後,可以直接在主函數使用:
在這裏插入圖片描述
使用r.Use 使用自己定義好的中間件,就可以對所有掛載的訪問路徑實現攔截功能。但是如果只是某些掛載的請求進行攔截,可以這樣:
在這裏插入圖片描述
這樣就不會進行全局的攔截。

middleware的一些應用場景

首先肯定是上面提到了,日誌記錄。然後還可以使用middleware做一些登錄的信息獲取以及鑑權。用戶在最開始登錄的時候,可以使用middleware給它一個cookie,然後再使用其他middleware就可以來獲取這些信息,從而判斷用戶當前的狀態,以及是不是具有權限等。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章