Golang原生http实现中间件

Golang原生http实现中间件

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

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

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

①CORSMiddleware:允许跨域

go 复制代码
// 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:认证

go 复制代码
// 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:审计操作

go 复制代码
// 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:具体处理操作

go 复制代码
// 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:定义中间件

go 复制代码
type Middleware func(http.Handler) http.Handler

②定义中间件链MiddlewareChain

go 复制代码
// 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服务

go 复制代码
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 复制代码
go run main.go
  1. 浏览器访问http://localhost:9999/smoke

  2. 后端日志打印

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

全部代码

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

go 复制代码
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()
}
相关推荐
吃着火锅x唱着歌1 小时前
Redis设计与实现 学习笔记 第五章 跳跃表
golang
技术卷4 小时前
Redis数据库与GO完结篇:redis操作总结与GO使用redis
数据库·redis·golang
一水鉴天4 小时前
智能工厂的软件设计 作为“程序Program”的中台
运维·人工智能·机器学习·中间件
中草药z5 小时前
【JavaEE】http/https 超级详解
网络·笔记·网络协议·学习·http·https·计网
white.tie7 小时前
vscode配置golang
ide·vscode·golang
陈序缘7 小时前
Go语言实现长连接并发框架 - 任务管理器
linux·服务器·开发语言·后端·golang
读心悦7 小时前
在 ArkTS 网络请求中,重新封装一下 http 模块
网络·网络协议·http
小灵蛇8 小时前
HTTP Cookie与Session
服务器·网络协议·http
学习使我快乐0111 小时前
AJAX 1——axios体验、认识URL、常用请求方法、HTTP协议、错误处理、form-serialize插件
前端·http·ajax·okhttp·axios
0x派大星11 小时前
【Golang】语法基础——切片:灵活、高效的数据处理利器
golang