欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 科技 > 能源 > go中间件学习

go中间件学习

2025/4/24 20:23:21 来源:https://blog.csdn.net/m0_37149062/article/details/146230853  浏览:    关键词:go中间件学习

本博文源于笔者正在学习go中间件,罗列了较为常用的中间件,例如日志记录、认证授权、跨域资源共享、请求体解析、静态文件处理、错误处理、性能分析、速率限制、session

1、日志记录中间件

可以追加打印用,例如,将请求进行打印

func logMiddleware(next http.Handler) http.Handler {return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {fmt.Printf("Request: %s %s\n", r.Method, r.URL)next.ServeHTTP(w, r)})
}

2、认证和授权中间件

对请求进行认证。

func authMiddleware(next http.Handler) http.Handler {return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {if r.Header.Get("API-Key") != "my-secret-key" {http.Error(w, "Unauthorized", http.StatusUnauthorized)return}next.ServeHTTP(w, r)})
}

3、跨域资源共享中间件

import "github.com/rs/cors"func handler(w http.ResponseWriter, r *http.Request) {w.Write([]byte("Hello World"))
}
func main() {fmt.Println("http://127.0.0.1:8082/")mux := http.NewServeMux()mux.HandleFunc("/", handler)c := cors.New(cors.Options{AllowedOrigins: []string{"*"},AllowedMethods: []string{"GET", "POST", "PUT", "DELETE"},AllowedHeaders: []string{"Content-Type"},})handlerWithCors := c.Handler(mux)log.Fatal(http.ListenAndServe(":8082", handlerWithCors))
}

4、请求体解析中间件

对请求体进行解析

package mainimport ("encoding/json""fmt""log""net/http"
)type Data struct {Name  string `json:"name"`Value string `json:"value"`
}func handler(w http.ResponseWriter, r *http.Request) {var data Dataerr := json.NewDecoder(r.Body).Decode(&data)if err != nil {http.Error(w, err.Error(), http.StatusBadRequest)return}response := map[string]interface{}{"message": "Hello " + data.Name + "!","data":    data,}w.Header().Set("Content-Type", "application/json")json.NewEncoder(w).Encode(response)
}func main() {fmt.Println("http://127.0.0.1:3000/api/data")//通过json包解析请求体中的json数据,并将其http.HandleFunc("/api/data", handler)log.Fatal(http.ListenAndServe(":3000", nil))
}

5、静态文件处理中间件

对服务器下的文件进行请求

package mainimport ("fmt""log""net/http"
)func main() {//提供static文件夹中的静态文件,用户可以通过访问下面的网站进行访问资源fmt.Println("http://127.0.0.1:3001/static/demo.png")fs := http.FileServer(http.Dir("static"))http.Handle("/static/", http.StripPrefix("/static/", fs))log.Fatal(http.ListenAndServe(":3001", nil))
}

6、错误处理中间件

遇到的错误可以方便进行recover处理

package mainimport ("fmt""log""net/http"
)// 错误处理中间件
func errorHandlingMiddleware(next http.Handler) http.Handler {return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {defer func() {if err := recover(); err != nil {http.Error(w, fmt.Sprintf("Internal Server Error: %v", err), http.StatusInternalServerError)}}()next.ServeHTTP(w, r)})
}func handler(w http.ResponseWriter, r *http.Request) {panic("Something went wrong!") // 模拟错误
}func main() {//通过panic与recover捕捉错误fmt.Println("http://127.0.0.1:3002/panic")mux := http.NewServeMux()mux.HandleFunc("/panic", handler)http.Handle("/", errorHandlingMiddleware(mux))log.Fatal(http.ListenAndServe(":3002", nil))
}

7、性能分析中间件

时间运行时统计的一个中间件

package mainimport ("fmt""log""net/http""time"
)func performanceMonitoringMiddleware(next http.Handler) http.Handler {return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {start := time.Now()next.ServeHTTP(w, r)duration := time.Since(start)fmt.Printf("Request took %v\n", duration)})
}func handler(w http.ResponseWriter, r *http.Request) {time.Sleep(2 * time.Second)w.Write([]byte("Hello World"))
}
func main() {//记录每个请求的处理时间,并输出在控制台。fmt.Println("http://127.0.0.1:3003")mux := http.NewServeMux()mux.HandleFunc("/", handler)http.Handle("/", performanceMonitoringMiddleware(mux))log.Fatal(http.ListenAndServe(":3003", nil))
}

8、缓存中间件

对缓存进行redis写入

package mainimport ("context""fmt""github.com/go-redis/redis/v8""log""net/http""time"
)var rdb *redis.Clientfunc initRedis() {rdb = redis.NewClient(&redis.Options{Addr: "localhost:6379",})
}func cacheMiddleware(next http.Handler) http.Handler {return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {key := r.URL.PathcachedValue, err := rdb.Get(context.Background(), key).Result()fmt.Println("!!!!!!", cachedValue, "??", err, "????", key)if err == nil {fmt.Println("Cache hit!")w.Write([]byte(cachedValue))return}fmt.Println("Cache miss.")next.ServeHTTP(w, r)rdb.Set(context.Background(), key, "This is the cached response", 60*time.Second)})
}func handler(w http.ResponseWriter, r *http.Request) {time.Sleep(1 * time.Second)w.Write([]byte("hello from the server"))
}func main() {initRedis()fmt.Println("http://127.0.0.1:3005")mux := http.NewServeMux()mux.HandleFunc("/", handler)http.Handle("/", cacheMiddleware(mux))log.Fatal(http.ListenAndServe(":3005", nil))
}

9、速率限制中间件

对速率限制,即对请求次数进行统计

package mainimport ("context""fmt""github.com/go-redis/redis/v8""log""net/http""time"
)var rdb *redis.Clientfunc initRedis() {rdb = redis.NewClient(&redis.Options{Addr: "localhost:6379",})
}func rateLimitMiddleware(next http.Handler) http.Handler {return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {ip := r.RemoteAddrkey := "rate_limit:" + ipcount, err := rdb.Get(context.Background(), key).Int()if err != nil && err != redis.Nil {http.Error(w, "Internal Server Error", http.StatusInternalServerError)return}if count >= 5 {http.Error(w, "Too many requests", http.StatusTooManyRequests)return}rdb.Incr(context.Background(), key)rdb.Expire(context.Background(), key, 1*time.Minute)next.ServeHTTP(w, r)})
}func handler(w http.ResponseWriter, r *http.Request) {w.Write([]byte("hello from the server"))
}func main() {initRedis()fmt.Println("http://127.0.0.1:3005")mux := http.NewServeMux()mux.HandleFunc("/", handler)http.Handle("/", rateLimitMiddleware(mux))log.Fatal(http.ListenAndServe(":3005", nil))
}

10、session中间件

通过第三方包来管理用户会话,中间件检查用户是否已通过身份验证,只有通过验证的用户才可以访问保护的页面

package mainimport ("fmt""log""net/http"
)import "github.com/gorilla/sessions"//通过三包来管理用户会话,中间件检查用户是否已通过身份验证,只有通过验证的用户才可以访问保护的页面var store = sessions.NewCookieStore([]byte("my-secret-key"))func sessionMiddleware(next http.Handler) http.Handler {return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {session, _ := store.Get(r, "session-name")//检查session是否存在if session.Values["authenticated"] == true {next.ServeHTTP(w, r)} else {http.Error(w, "Forbidden", http.StatusForbidden)}})
}func loginHandler(w http.ResponseWriter, r *http.Request) {session, _ := store.Get(r, "session-name")session.Values["authenticated"] = truesession.Save(r, w)fmt.Fprintln(w, "You are logged in!")}func main() {fmt.Println("http://127.0.0.1:8082/login")fmt.Println("http://127.0.0.1:8082/protected")mux := http.NewServeMux()mux.HandleFunc("/login", loginHandler)mux.Handle("/protected", sessionMiddleware(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {fmt.Fprintln(w, "You have access to this page")})))log.Fatal(http.ListenAndServe(":8082", mux))
}

11、请求数据验证中间件

对数据进行验证

package mainimport ("encoding/json""fmt""github.com/go-playground/validator/v10""log""net/http"
)// 用户结构体,用于验证
type User struct {Name  string `json:"name" validate:"required"`Email string `json:"email" validate:"required,email"`
}// 数据验证中间件
func validationMiddleware(next http.Handler) http.Handler {return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {// 解析请求体中的 JSON 数据var user Userdecoder := json.NewDecoder(r.Body)if err := decoder.Decode(&user); err != nil {http.Error(w, "Invalid request body", http.StatusBadRequest)return}// 验证数据validate := validator.New()if err := validate.Struct(user); err != nil {http.Error(w, fmt.Sprintf("Validation failed: %v", err), http.StatusBadRequest)return}// 验证通过,继续处理请求next.ServeHTTP(w, r)})
}func handler(w http.ResponseWriter, r *http.Request) {w.Write([]byte("User data is valid!"))
}func main() {mux := http.NewServeMux()mux.HandleFunc("/user", handler)// 包装请求处理器,加入数据验证中间件http.Handle("/user", validationMiddleware(mux))log.Fatal(http.ListenAndServe(":3000", nil))
}

12、压缩中间件

对请求头进行查阅,观察是否需要压缩

package mainimport ("compress/gzip""fmt""log""net/http""strings"
)func compressionMiddleware(next http.Handler) http.Handler {return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {if strings.Contains(r.Header.Get("Accept-Encoding"), "gzip") {w.Header().Set("Content-Encoding", "gzip")gz := gzip.NewWriter(w)defer gz.Close()gzw := &gzipResponseWriter{Writer: gz, ResponseWriter: w}next.ServeHTTP(gzw, r)} else {next.ServeHTTP(w, r)}})
}type gzipResponseWriter struct {http.ResponseWriterWriter *gzip.Writer
}func (g *gzipResponseWriter) Write(b []byte) (int, error) {return g.Writer.Write(b)
}func handler(w http.ResponseWriter, r *http.Request) {responseText := "This is a test response that will be compressed if the client supports Gzip.\n"for i := 0; i < 5; i++ {responseText += responseText}w.Write([]byte(responseText))
}func main() {fmt.Println("http://127.0.0.1:8085/")mux := http.NewServeMux()mux.HandleFunc("/", handler)http.Handle("/", compressionMiddleware(mux))log.Fatal(http.ListenAndServe(":8085", nil))
}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词