Golang原生http实现中间件

2024-06-01 1398阅读

Golang原生http实现中间件

中间件(middleware):常被用来做认证校验、审计等

  • 大家常用的Iris、Gin等web框架,都包含了中间件逻辑。但有时我们引入该框架显得较为繁重,本文将介绍通过golang原生http来实现中间件操作。
  • 全部代码:https://github.com/ziyifast/ziyifast-code_instruction/tree/main/middleware

    1 定义http.Handler:具体中间件操作

    ①CORSMiddleware:允许跨域

    // CORSMiddleware handles Cross-Origin Resource Sharing (CORS) responses.
    func CORSMiddleware(next http.Handler) http.Handler {
    	fmt.Println("cors middleware....")
    	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    		if r.Method == "OPTIONS" {
    			w.Header().Set("Access-Control-Allow-Origin", "*")
    			w.Header().Set("Access-Control-Allow-Methods", "GET, POST, OPTIONS, DELETE")
    			//如果前后端需要传递自定义请求头,需要再Access-Control-Allow-Headers中匹配(Yi-Auth-Token)
    			w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Accept, Yi-Auth-Token")
    			w.WriteHeader(http.StatusOK)
    			return
    		}
    		w.Header().Set("Access-Control-Allow-Origin", "*")
    		w.Header().Set("Access-Control-Allow-Methods", "GET, POST, OPTIONS, DELETE")
    		w.Header().Set("Access-Control-Allow-Headers", "Content-Type,Accept,Yi-Auth-Token")
    		//交给下一个中间件处理
    		next.ServeHTTP(w, r)
    	})
    }
    

    ②AuthMiddleware:认证

    // AuthMiddleware simulates a simple authentication middleware.
    func AuthMiddleware(next http.Handler) http.Handler {
    	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    		fmt.Println("auth middleware...")
    		//store info in ctx
    		token := r.Header.Get("Token")
    		if len(token) != 0 {
    			//TODO 1. check token 2. get userinfo from token
    			userID := "1"
    			ctx := context.WithValue(r.Context(), "userID", userID)
    			r = r.WithContext(ctx)
    		}
    		next.ServeHTTP(w, r)
    	})
    }
    

    ③AuditMiddleware:审计操作

    // AuditMiddleware simulates an audit logging middleware.
    func AuditMiddleware(next http.Handler) http.Handler {
    	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    		fmt.Println("audit middleware...")
    		next.ServeHTTP(w, r)
    	})
    }
    

    ④SmokeHandler:具体处理操作

    // SmokeHandler returns the current time as a string.
    func SmokeHandler(w http.ResponseWriter, r *http.Request) {
    	fmt.Println("smoke handle....")
    	_, err := w.Write([]byte(time.Now().String()))
    	if err != nil {
    		http.Error(w, "Internal Server Error", http.StatusInternalServerError)
    	}
    }
    

    2 义中间件类型&定义中间件链

    ①type Middleware func(http.Handler) http.Handler:定义中间件

    type Middleware func(http.Handler) http.Handler
    

    ②定义中间件链MiddlewareChain

    // NewMiddlewareChain creates a new middleware chain with the given middlewares.
    func NewMiddlewareChain(middlewares ...Middleware) Middleware {
    	return func(handler http.Handler) http.Handler {
    		for i := len(middlewares) - 1; i >= 0; i-- {
    			handler = middlewares[i](handler)
    		}
    		return handler
    	}
    }
    

    3 启动http服务

    func RunAndServe() error {
    	defer func() {
    		if e := recover(); e != nil {
    			fmt.Println("err=", e)
    		}
    	}()
    	mux := http.NewServeMux()
    	// Create middleware chains for routes.
    	authMiddlewareChain := NewMiddlewareChain(CORSMiddleware, AuthMiddleware, AuditMiddleware)
    	//noAuthMiddlewareChain := NewMiddlewareChain(CORSMiddleware)
    	// Convert the middleware chain result to http.HandlerFunc.
    	smokeHandlerWrapped := func(w http.ResponseWriter, r *http.Request) {
    		authMiddlewareChain(http.HandlerFunc(SmokeHandler)).ServeHTTP(w, r)
    	}
    	mux.HandleFunc("/smoke", smokeHandlerWrapped)
    	fmt.Printf("listening on http://localhost:%d\n", 9999)
    	return http.ListenAndServe(":9999", mux)
    }
    

    4 测试

    1. 启动后端
    go run main.go
    

    Golang原生http实现中间件

    2. 浏览器访问http://localhost:9999/smoke

    Golang原生http实现中间件

    3. 后端日志打印

    可以看到是最后才处理我们的业务Handler

    Golang原生http实现中间件

    全部代码

    🚀:https://github.com/ziyifast/ziyifast-code_instruction/tree/main/middleware

    package main
    import (
    	"context"
    	"fmt"
    	"net/http"
    	"time"
    )
    type Middleware func(http.Handler) http.Handler
    // CORSMiddleware handles Cross-Origin Resource Sharing (CORS) responses.
    func CORSMiddleware(next http.Handler) http.Handler {
    	fmt.Println("cors middleware....")
    	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    		if r.Method == "OPTIONS" {
    			w.Header().Set("Access-Control-Allow-Origin", "*")
    			w.Header().Set("Access-Control-Allow-Methods", "GET, POST, OPTIONS, DELETE")
    			//如果前后端需要传递自定义请求头,需要再Access-Control-Allow-Headers中匹配(Yi-Auth-Token)
    			w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Accept, Yi-Auth-Token")
    			w.WriteHeader(http.StatusOK)
    			return
    		}
    		w.Header().Set("Access-Control-Allow-Origin", "*")
    		w.Header().Set("Access-Control-Allow-Methods", "GET, POST, OPTIONS, DELETE")
    		w.Header().Set("Access-Control-Allow-Headers", "Content-Type,Accept,Yi-Auth-Token")
    		next.ServeHTTP(w, r)
    	})
    }
    // AuthMiddleware simulates a simple authentication middleware.
    func AuthMiddleware(next http.Handler) http.Handler {
    	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    		fmt.Println("auth middleware...")
    		//store info in ctx
    		token := r.Header.Get("Token")
    		if len(token) != 0 {
    			//TODO 1. check token 2. get userinfo from token
    			userID := "1"
    			ctx := context.WithValue(r.Context(), "userID", userID)
    			r = r.WithContext(ctx)
    		}
    		next.ServeHTTP(w, r)
    	})
    }
    // AuditMiddleware simulates an audit logging middleware.
    func AuditMiddleware(next http.Handler) http.Handler {
    	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    		fmt.Println("audit middleware...")
    		next.ServeHTTP(w, r)
    	})
    }
    // SmokeHandler returns the current time as a string.
    func SmokeHandler(w http.ResponseWriter, r *http.Request) {
    	fmt.Println("smoke handle....")
    	_, err := w.Write([]byte(time.Now().String()))
    	if err != nil {
    		http.Error(w, "Internal Server Error", http.StatusInternalServerError)
    	}
    }
    // NewMiddlewareChain creates a new middleware chain with the given middlewares.
    func NewMiddlewareChain(middlewares ...Middleware) Middleware {
    	return func(handler http.Handler) http.Handler {
    		for i := len(middlewares) - 1; i >= 0; i-- {
    			handler = middlewares[i](handler)
    		}
    		return handler
    	}
    }
    func RunAndServe() error {
    	defer func() {
    		if e := recover(); e != nil {
    			fmt.Println("err=", e)
    		}
    	}()
    	mux := http.NewServeMux()
    	// Create middleware chains for routes.
    	authMiddlewareChain := NewMiddlewareChain(CORSMiddleware, AuthMiddleware, AuditMiddleware)
    	//noAuthMiddlewareChain := NewMiddlewareChain(CORSMiddleware)
    	// Convert the middleware chain result to http.HandlerFunc.
    	smokeHandlerWrapped := func(w http.ResponseWriter, r *http.Request) {
    		authMiddlewareChain(http.HandlerFunc(SmokeHandler)).ServeHTTP(w, r)
    	}
    	mux.HandleFunc("/smoke", smokeHandlerWrapped)
    	fmt.Printf("listening on http://localhost:%d\n", 9999)
    	return http.ListenAndServe(":9999", mux)
    }
    func main() {
    	RunAndServe()
    }
    
VPS购买请点击我

免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们,邮箱:ciyunidc@ciyunshuju.com。本站只作为美观性配图使用,无任何非法侵犯第三方意图,一切解释权归图片著作权方,本站不承担任何责任。如有恶意碰瓷者,必当奉陪到底严惩不贷!

目录[+]