Golang原生http实现中间件

news2024/11/19 7:25:26

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

在这里插入图片描述
2. 浏览器访问http://localhost:9999/smoke
在这里插入图片描述
3. 后端日志打印

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

在这里插入图片描述

全部代码

🚀: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()
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1710244.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

vue复习选择题2

1. 下面哪一个方法可以实现判断元素的class属性是否含有pp样式? (A) A. hasClass(“pp”)B. is(“pp”)C. attr(“class”,“pp”)D. toggleClass(“pp”) [!NOTE] 当涉及到在 jQuery 中判断元素的类属性时,下面是各个选项的作用…

2024/5/28 P1247 取火柴游戏

取火柴游戏 题目描述 输入 k k k 及 k k k 个整数 n 1 , n 2 , ⋯ , n k n_1,n_2,\cdots,n_k n1​,n2​,⋯,nk​,表示有 k k k 堆火柴棒,第 i i i 堆火柴棒的根数为 n i n_i ni​;接着便是你和计算机取火柴棒的对弈游戏。取的规则如下&…

AI批量剪辑视频素材,高效混剪快速出片/矩阵发布,一键管理自媒体账号。

今天给大家分享一个超级好用的办公神器。特别是玩矩阵的企业,这款工具高效解决短视频剪辑问题。 这款软件可以帮你快速生产出1000条视频内容,而且还能把内容同步到多个平台账号上,多平台矩阵发布。 这款系统真的太棒了! 不仅操作简单,而且功能超强大。 …

干冰清洗机的清洗原理及应用

干冰清洗机的清洗原理及应用可以详细阐述如下: 一、清洗原理 干冰清洗机的清洗原理主要基于干冰的低温冷冻作用。干冰在常温下会迅速升华,吸收大量的热量,使周围的温度迅速降低。当干冰颗粒通过特殊的干冰清洗机喷射到清洗物体表面时&#…

Python | Leetcode Python题解之第104题二叉树的最大深度

题目: 题解: class Solution:def maxDepth(self, root: TreeNode) -> int:if not root: return 0queue, res [root], 0while queue:tmp []for node in queue:if node.left: tmp.append(node.left)if node.right: tmp.append(node.right)queue tmp…

素数判断的奥秘与编程实践

新书上架~👇全国包邮奥~ python实用小工具开发教程http://pythontoolsteach.com/3 欢迎关注我👆,收藏下次不迷路┗|`O′|┛ 嗷~~ 目录 一、素数定义的深入理解 二、非素数的例子与思考 三、素数判断的编程实现 1. 穷举法判断素…

多语言印度红绿灯系统源码带三级分销代理功能

前端为2套UI,一套是html写的,一套是编译后的前端 后台功能很完善,带预设、首充返佣、三级分销机制、代理功能。 东西很简单,首页就是红绿灯的下注页面,玩法虽然单一,好在不残缺可以正常跑。

SD Flash介绍

作为一家专业生产存储芯片及存储卡的原厂,我们时常收到客户关于SD Flash的各种技术问题。MK米客方德将详细解答关于SD Flash的常见问题,助您更好地了解这一重要存储技术。 SD Flash是一种常见的存储卡技术,广泛应用于各种便携式设备中&#x…

无人机+EasyDSS互联网视频平台:构建秸秆焚烧监控的“天眼”系统

一、方案背景 在每年的夏收时节,秸秆禁烧成为各地政府面临的一项重要任务。随着夏收季节的结束,大量农作物秸秆的处理问题逐渐凸显。一方面农作物种植面积辽阔,禁烧区域面积较大,监管巡逻人员的数量有限,无法全面顾及…

微软提出“Copilot+ PCs”构想,强调本地AI处理;OpenAI暂停ChatGPT语音功能因声音相似争议

🦉 AI新闻 🚀 微软提出“Copilot PCs”构想,强调本地AI处理 摘要:在微软 Build 开发者前瞻大会上,CEO 萨蒂亚・纳德拉介绍了“Copilot PCs”,一种新类 Windows PC,需配备神经处理单元&#xf…

centos7单机安装openstack

前提:如果你使用 VMware 一定要打开 虚拟化,点设置->处理器下面有一些选项,一定要勾选,如下图所示,勾选后,启动系统后使用lscpu查看 virtaulization 是否正确 1.更新yum源: #yum update2.关闭…

2024年,史上最强的数据库资料集合

💨🏹🌀 2024年,史上最强的数据库资料集合 N种数据库的全方位整理: mysql,mariaDB,Percona Server,Redis,RocksDB,Cassandra,CouchDB&#xff0c…

【平渊随笔】我们为什么要复盘?吸取教训,予其惩,而毖后患!

《平渊》 肆 "予其惩,而毖后患" "复盘" 一词源于围棋术语,对弈者完成一局棋后,重新摆局,审视棋局中的优势与失误,看哪些地方下得好,哪些地方下得不好,有没有更优解&#xf…

(四)MySQL 事务

欢迎访问 事务有哪些特性? 事务是由 MySQL 的引擎来实现的,我们常见的 InnoDB 引擎它是支持事务的。 不过并不是所有的引擎都能支持事务,比如 MySQL 原生的 MyISAM 引擎就不支持事务,也正是这样,所以大多数 MySQL 的…

【Java EE】网络原理——HTTP请求

目录 1.认识URL 2.认识“方法(method)” 2.1GET方法 2.1.1使用Fiddler观察GET请求 2.1.2 GET请求的特点 2.2 POST方法 2.2.1 使用FIddler观察POST方法 2.2.2 POST请求的特点 3.认识请求“报头”(header) 3.1 Host 3.2 C…

力扣算法之1068. 产品销售分析 I

力扣传送门 题解 同时输出a,b两张表上的数据 我的解 SELECT product_name,year,price FROM Sales a LEFT JOIN Product b ON a.product_id b.product_id我的解注解 考sql联表语法

【软考】系统架构师知识点

目录 环路复杂度McCabe软件工具分类需求分类软件测试中间件分类等保(信息安全等级保护)数据流图DFD微内核架构信息系统生命周期区块链MDA模型驱动架构EJBSOA微服务REST五大原则管道过滤器 VS 仓库风格虚拟机风格质量属性 & 非功能性需求敏感点、权衡…

pdf编辑器推荐,这三款软件十分好用!

在数字化时代,PDF文档因其跨平台、易阅读的特性,成为了我们工作、学习、生活中不可或缺的一部分。然而,如何高效、便捷地编辑PDF文档,却成为许多人面临的难题。今天,就为大家推荐三款十分好用的PDF编辑器,让…

精酿啤酒:品质与口感对啤酒市场价格的影响

啤酒作为一种大众化的产品,其品质与口感对市场价格有着显著的影响。对于Fendi club啤酒而言,其卓着的品质和与众不同的口感又加上市场价格相对实惠,受到消费者的青睐。 品质是决定啤酒市场价格的重要因素。Fendi club啤酒选用天然小麦原料&am…

大数据技术之Scala语言,只需一篇文章即可,教你学会什么是Scala,教你如何使用Scala

一丶Scala入门 1.1什么是Scala Scala是Scalable Language两个单词的缩写,表示可伸缩语言的意思。从计算机的角度来讲,Scala是一门完整的软件编程语言,那么连在一起就表示Scala是一门可伸缩的软件编程语言。之所以说它是可伸缩,是…