go 微服務(wù)框架kratos使用中間件的方法
一、中間件的概念
在go語言中,中間件是一種用于處理http請(qǐng)求的開發(fā)模式,允許開發(fā)人員在請(qǐng)求到達(dá)處理程序之前或之后執(zhí)行特定的操作,如日志記錄、身份驗(yàn)證、錯(cuò)誤處理等。
中間件通常是一個(gè)函數(shù),它接收一個(gè) `http.Handler` 作為參數(shù)并返回另一個(gè) `http.Handler`。
go源碼中 Handler 的定義如下:
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}二、go原生http中使用中間件的方法
使用方法:
1、創(chuàng)建中間件函數(shù),輸入?yún)?shù) http.Handler,輸出參數(shù) http.Handler
2、將處理器函數(shù)作為參數(shù)傳入上述中間件函數(shù)
3、運(yùn)用 Handle(pattern string, handler Handler) 等函數(shù)將中間件函數(shù)綁定到請(qǐng)求路由中
代碼示例:
package main
import (
"fmt"
"log"
"net/http"
)
// 日志記錄中間件
func loggingMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
log.Printf("請(qǐng)求處理之前 Request URI: %s\n", r.RequestURI)
next.ServeHTTP(w, r)
log.Printf("處理程序之后進(jìn)行的操作...\n")
})
}
// handler 處理函數(shù)
func SayHello(w http.ResponseWriter, r *http.Request) {
fmt.Println("Hello world")
}
func main() {
//創(chuàng)建一個(gè) HTTP 請(qǐng)求路由器
mux := http.NewServeMux()
// 使用日志記錄中間件
mux.Handle("/index", loggingMiddleware(http.HandlerFunc(SayHello)))
//啟動(dòng)服務(wù),使用創(chuàng)建的 ServeMux
http.ListenAndServe(":8081", mux)
}運(yùn)行效果:

三、go微服務(wù)框架Kratos使用中間件的方法
kratos介紹中間件的官網(wǎng)地址:概覽 | Kratos
1、內(nèi)置中間件使用方法
①通過 Middleware(m ...middleware.Middleware) ServerOption 添加所需的中間件
②將上述由中間件組成的 ServerOption 添加到 []http.ServerOption 中
③通過函數(shù) NewServer(opts ...ServerOption) *Server 創(chuàng)建 httpServer
代碼示例:
func NewHTTPServer(c *conf.Server, logger log.Logger, blog *service.BlogService) *http.Server {
opts := []http.ServerOption{
http.Middleware(
//使用kratos內(nèi)置中間件
recovery.Recovery(),
tracing.Server(),
logging.Server(logger),
validate.Validator(),
),
}
if c.Http.Network != "" {
opts = append(opts, http.Network(c.Http.Network))
}
if c.Http.Addr != "" {
opts = append(opts, http.Address(c.Http.Addr))
}
if c.Http.Timeout != nil {
opts = append(opts, http.Timeout(c.Http.Timeout.AsDuration()))
}
//創(chuàng)建 httpServer
srv := http.NewServer(opts...)
v1.RegisterBlogServiceHTTPServer(srv, blog)
return srv
}2、自定義中間件使用方法
①實(shí)現(xiàn) middleware.Middleware 接口,其定義如下:
// Handler defines the handler invoked by Middleware.
type Handler func(ctx context.Context, req interface{}) (interface{}, error)
// Middleware is HTTP/gRPC transport middleware.
type Middleware func(Handler) Handler中間件中您可以使用 tr, ok := transport.FromServerContext(ctx) 獲得 Transporter 實(shí)例以便訪問接口相關(guān)的元信息。
②像添加內(nèi)置中間件一樣,將自定義中間件添加到 http.Middleware 和 []http.ServerOption 中
③通過函數(shù) NewServer(opts ...ServerOption) *Server 創(chuàng)建 httpServer
代碼示例:
// auth.go 單元
//自定義 JWT 認(rèn)證中間件
func JWTAuth(jwtSecret string) middleware.Middleware {
return func(handler middleware.Handler) middleware.Handler {
return func(ctx context.Context, req interface{}) (reply interface{}, err error) {
if tr, ok := transport.FromServerContext(ctx); ok {
tokenString := tr.RequestHeader().Get("authorization")
spew.Dump(tokenString)
//token, err := jwt.ParseWithClaims(tokenString, &jwt.StandardClaims{}, func(token *jwt.Token) (interface{}, error) {
token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
// Don't forget to validate the alg is what you expect:
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"])
}
// hmacSampleSecret is a []byte containing your secret, e.g. []byte("my_secret_key")
return []byte(jwtSecret), nil
})
if err != nil {
log.Fatal(err)
}
if claims, ok := token.Claims.(jwt.MapClaims); ok {
fmt.Println(claims["iss"], claims["exp"])
//fmt.Println(claims.Issuer, claims.ExpiresAt)
} else {
fmt.Println(err)
}
}
return handler(ctx, req)
}
}
}
// server/http.go 單元
func NewHTTPServer(c *conf.Server, confAuth *conf.Auth, logger log.Logger, blog *service.BlogService) *http.Server {
opts := []http.ServerOption{
http.Middleware(
//自定義中間件 JWTAuth
auth.JWTAuth(confAuth.JwtSecrect),
),
}
if c.Http.Network != "" {
opts = append(opts, http.Network(c.Http.Network))
}
if c.Http.Addr != "" {
opts = append(opts, http.Address(c.Http.Addr))
}
if c.Http.Timeout != nil {
opts = append(opts, http.Timeout(c.Http.Timeout.AsDuration()))
}
//創(chuàng)建 httpServer
srv := http.NewServer(opts...)
v1.RegisterBlogServiceHTTPServer(srv, blog)
return srv
}3、為特定路由定制中間件的使用方法
使用方法:
對(duì)特定路由定制中間件:
server: selector.Server(ms...)
client: selector.Client(ms...)
代碼示例:
// server/http.go 單元
// 添加驗(yàn)證白名單
func NewWhiteListMatcher() selector.MatchFunc {
whiteList := make(map[string]struct{})
whiteList["/blog.api.v1.Account/Login"] = struct{}{}
whiteList["/blog.api.v1.Account/Register"] = struct{}{}
return func(ctx context.Context, operation string) bool {
if _, ok := whiteList[operation]; ok {
return false
}
return true
}
}
// server/http.go 單元
func NewHTTPServer(c *conf.Server, confAuth *conf.Auth, logger log.Logger, blog *service.BlogService) *http.Server {
opts := []http.ServerOption{
http.Middleware(
//自定義中間件 JWTAuth
selector.Server(auth.JWTAuth(confAuth.JwtSecrect)).
Match(NewWhiteListMatcher()).
Build(),
),
}
if c.Http.Network != "" {
opts = append(opts, http.Network(c.Http.Network))
}
if c.Http.Addr != "" {
opts = append(opts, http.Address(c.Http.Addr))
}
if c.Http.Timeout != nil {
opts = append(opts, http.Timeout(c.Http.Timeout.AsDuration()))
}
//創(chuàng)建 httpServer
srv := http.NewServer(opts...)
v1.RegisterBlogServiceHTTPServer(srv, blog)
return srv
}注意: 定制中間件是通過 operation 匹配,并不是 http 本身的路由!??!
gRPC path 的拼接規(guī)則為 /包名.服務(wù)名/方法名(/package.Service/Method)。
到此這篇關(guān)于go 微服務(wù)框架kratos使用中間件的方法的文章就介紹到這了,更多相關(guān)go 微服務(wù)框架kratos使用中間件內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- goZero微服務(wù)開發(fā)小結(jié)
- Go語言gRPC實(shí)現(xiàn)高性能微服務(wù)通信
- golang微服務(wù)框架Kratos實(shí)現(xiàn)消息隊(duì)列
- Go語言微服務(wù)中實(shí)現(xiàn)鏈路追蹤
- Golang微服務(wù)框架Kratos實(shí)現(xiàn)Kafka消息隊(duì)列的方法
- Go語言從單體服務(wù)到微服務(wù)設(shè)計(jì)方案詳解
- 詳解go-micro微服務(wù)consul配置及注冊(cè)中心
- go?micro微服務(wù)框架項(xiàng)目搭建方法
- 手把手教你go frame 2.x版本搭建微服務(wù)
相關(guān)文章
golang基礎(chǔ)之Gocurrency并發(fā)
這篇文章主要介紹了golang基礎(chǔ)之Gocurrency并發(fā),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-07-07
Go?channel實(shí)現(xiàn)批量讀取數(shù)據(jù)
Go中的?channel?其實(shí)并沒有提供批量讀取數(shù)據(jù)的方法,需要我們自己實(shí)現(xiàn)一個(gè),使用本文就來為大家大家介紹一下如何通過Go?channel實(shí)現(xiàn)批量讀取數(shù)據(jù)吧2023-12-12
Go實(shí)現(xiàn)map轉(zhuǎn)json的示例詳解
這篇文章主要為大家詳細(xì)介紹了如何利用Go語言實(shí)現(xiàn)map轉(zhuǎn)json的功能,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2023-09-09
深入學(xué)習(xí)Golang并發(fā)編程必備利器之sync.Cond類型
Go?語言的?sync?包提供了一系列同步原語,其中?sync.Cond?就是其中之一。本文將深入探討?sync.Cond?的實(shí)現(xiàn)原理和使用方法,幫助大家更好地理解和應(yīng)用?sync.Cond,需要的可以參考一下2023-05-05
go語法入門泛型type?parameters簡稱T(類型形參)兩種場景使用
這篇文章主要為大家介紹了go語法入門泛型type?parameters簡稱T(類型形參)兩種場景使用示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-09-09

