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()
}
相关推荐
独泪了无痕1 天前
使用Fetch API 探索前后端数据交互
前端·http·交互设计
小红卒1 天前
Go语言安全开发学习笔记1:Windows反向TCP反弹Shell 原理与代码
golang
lisus20071 天前
GO并发统计文件大小
开发语言·后端·golang
Hello World . .1 天前
Linux:网络编程-基于HTTP协议的天气预报查询系统开发详解
linux·网络·http
lars_lhuan1 天前
Go 并发
golang
Reisentyan1 天前
GoLang Learn Data Day 0
开发语言·rpc·golang
NPE~1 天前
[爬虫]获取某鱼网页版商品数据
爬虫·python·教程·逆向
lzp07912 天前
【中间件】Pulsar集群安装
中间件
读研的武2 天前
Golang学习笔记 入门篇
笔记·学习·golang
初中就开始混世的大魔王2 天前
2 Fast DDS Library概述
c++·中间件·信息与通信