Golang原生http实现中间件

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 ctxtoken := r.Header.Get("Token")if len(token) != 0 {//TODO 1. check token 2. get userinfo from tokenuserID := "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 mainimport ("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 ctxtoken := r.Header.Get("Token")if len(token) != 0 {//TODO 1. check token 2. get userinfo from tokenuserID := "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.mzph.cn/diannao/18001.shtml

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

相关文章

《中国科技投资》是什么级别的期刊?是正规期刊吗?能评职称吗?

问题解答: 问:《中国科技投资》期刊什么级别? 答:国家级 问:《中国科技投资》期刊是核心期刊吗? 答:不是,是万方维普收录的正规期刊。 主管单位:中国信息协会 主办单位&#…

【云原生_K8S系列】认识 Kubernetes

在当今数字化转型的浪潮中,企业对于构建高效、灵活的软件架构有了更高的期望。而在这个迅速变化的环境中,容器化技术如雨后春笋般涌现,为解决传统部署和管理软件所带来的挑战提供了一种全新的解决方案。在众多容器编排工具中,Kube…

5G专网驻网失败分析(suci无效)

suci 5G终端第一次驻网时,注册消息Registartion request中携带的5GS mobile identity要携带suci类型的mobile identity。 注册消息协议规范见5G NAS 协议3gpp TS24.501 8.2.6 Registration request。 suci协议规范参见3gpp TS24.501 9.11.3.4 5GS mobile identity …

Kubernetes Service 之原理与 ClusterIP 和 NodePort 用法

Kubernetes Service 之原理与 ClusterIP 和 NodePort 用法 Service 定义 在 Kubernetes 中,由于Pod 是有生命周期的,如果 Pod 重启它的 IP 可能会发生变化以及升级的时候会重建 Pod,我们需要 Service 服务去动态的关联这些 Pod 的 IP 和端口…

防止浏览器缓存了静态的配置等文件(例如外部的config.js 等文件)

防止浏览器缓存了静态的配置文件 前言1、在script引入的时候添加随机数1.1、引入js文件1.2、引入css文件2、通过html文件的<meta>设置防止缓存3、使用HTTP响应头:前言 在实际开发中浏览器的缓存问题一直是一个很让人头疼的问题,尤其是我们打包时候防止的静态配置文件c…

openssh9.7p1(OpenSSL 1.1.1w)适用于各Linux系统的rpm包

本人近几日编译的openssh9.7p1包&#xff0c;用于解决漏洞扫描器提示openssh相关漏洞的问题处理。 包含多个Linux发行版本&#xff08;包含el6\el7\el8\openeuler2110\openeuler2203\BCLinux\eulerOS2.10对应版本等&#xff09;。 一、适用openeuler2203和openeuler2203 sp*系…

界面组件DevExpress WPF v23.2新版亮点:富文本编辑器、电子表格组件升级

DevExpress WPF拥有120个控件和库&#xff0c;将帮助您交付满足甚至超出企业需求的高性能业务应用程序。通过DevExpress WPF能创建有着强大互动功能的XAML基础应用程序&#xff0c;这些应用程序专注于当代客户的需求和构建未来新一代支持触摸的解决方案。 DevExpress WPF控件日…

FreeRtos进阶——消息队列的操作逻辑

消息队列&#xff08;queue&#xff09; 在不同的任务之间&#xff0c;如果我们需要互相之间通信&#xff0c;使用全局变量进行通信&#xff0c;是一种不安全的通信的方式。为保证线程安全&#xff0c;我们需要引入消息队列的通信方式。 粗暴的消息队列 为保证线程的安全&am…

如何手搓一个RAG

如何手搓一个RAG RAG的原理 RAG 是一个完整的系统&#xff0c;其工作流程可以简单地分为数据处理、检索、增强和生成四个阶段&#xff1a; 数据处理阶段 对原始数据进行清洗和处理。将处理后的数据转化为检索模型可以使用的格式。将处理后的数据存储在对应的数据库中。 检索…

趣店集团golang一面要个20K,Channel什么情况下会出现死锁,有遇到过吗?

结束后面试官加了VX&#xff0c;并询问方便二面的时间&#xff0c;一直还没回复&#xff0c;拖着拖着给忘啦... 面试题 1、自我介绍 2、你在团队里头负责哪一块&#xff0c;这个物流开放平台流量多大 3、为什么今年3月份被从物流开放团队转到了finance财务部门&#xff0c;感…

hadoop学习之MapReduce案例:输出每个班级中的成绩前三名的学生

hadoop学习之MapReduce案例&#xff1a;输出每个班级中的成绩前三名的学生 所要处理的数据案例&#xff1a; 1500100001 施笑槐,22,女,文科六班,406 1500100002 吕金鹏,24,男,文科六班,440 1500100003 单乐蕊,22,女,理科六班,359 1500100004 葛德曜,24,男,理科三班,421 15001…

安全术语 | 软件包purl详解:跨工具、数据库、API和语言之间可靠地识别和定位软件包

软件包URL&#xff08;purl&#xff0c;Package URL&#xff09;是一个URL字符串&#xff0c;用于在编程语言、包管理器、包约定、工具、API和数据库中以最通用和统一的方式识别和定位软件包。purl是对现有方法进行标准化的尝试&#xff0c;以可靠地识别和定位软件包。 有望取代…

集合的创建

自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 Python中的集合同数学中的集合概念类似&#xff0c;也是用于保存不重复元素的。它有可变集合&#xff08;set&#xff09;和不可变集合&#xff08;f…

网络学习(九)|深入解析Cookie与Session:高级应用及安全实践

Cookie相关问题 Cookie的主要属性有哪些&#xff1f; Cookie的主要属性包括&#xff1a; name&#xff1a;Cookie的名称。value&#xff1a;Cookie的值。domain&#xff1a;Cookie所属的域。path&#xff1a;Cookie生效的路径。expires / max-age&#xff1a;Cookie的过期时…

网络学习(十) | 深入学习HTTPS与安全传输

文章目录 HTTPS与HTTP的关系基本概念主要区别关系发展趋势 HTTPS的加密原理与SSL/TLS协议加密原理加密机制总结 HTTPS的握手vs三次握手三次握手HTTPS握手过程区别总结 证书颁发机构&#xff08;CA&#xff09;与数字证书的验证证书颁发机构&#xff08;CA&#xff09;CA的主要功…

vue的axios配置超时时间;单个接口配置响应时间

vue项目中axios请求统一配置了超时时间&#xff0c;单独接口请求时重设超时时间 根据官网推荐&#xff1a;axios中文文档 1.配置的优先顺序 配置会以一个优先顺序进行合并。这个顺序是&#xff1a;在 lib/defaults.js 找到的库的默认值&#xff0c;然后是实例的 defaults 属性&…

【iOS】——GCD再学习

文章目录 一、GCD的定义二、GCD 任务和队列1.任务2.队列 三、GCD 的使用1.创建队列2.创建任务3.队列任务 组合方式并发队列 同步执行异步执行 并发队列同步执行 串行队列异步执行 串行队列同步执行 主队列在主线程中调用 同步执行 主队列在其它线程中调用 同步执行 主队…

四数相加Ⅱ-力扣

做这道题想到的解法是&#xff0c;由于该题只统计元组个数&#xff0c;而不需要位置&#xff0c;那我们首先用一个map来统计数组1和数组2两两元素之和出现的个数&#xff0c;然后去遍历数组3和数组4&#xff0c;在map中寻找 0 - c - d 这个键值是否存在&#xff08;c和d为数组3…

uniApp 创建Android.keystore证书IOS的证书

Android 证书 1、安装JRE环境 可从Oracle官方下载jre安装包&#xff1a;https://www.oracle.com/technetwork/java/javase/downloads/index.html 打开命令行&#xff08;cmd&#xff09;&#xff0c;输入以下命令&#xff1a; //切换工作目录到f:路径 D: //将jre命令添加到…

2024/5/22 Day36 greedy 1005.K次取反后最大化的数组和 134. 加油站 135. 分发糖果

2024/5/22 Day36 greedy 1005.K次取反后最大化的数组和 134. 加油站 135. 分发糖果 1005.K次取反后最大化的数组和 题目链接 1005 给你一个整数数组 nums 和一个整数 k &#xff0c;按以下方法修改该数组&#xff1a; 选择某个下标 i 并将 nums[i] 替换为 -nums[i] 。 重复这…