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…

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

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

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

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

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

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

安全术语 | 软件包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…

【iOS】——GCD再学习

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

Android制作.9图

需求背景&#xff1a;android 启动图变形 开发语言&#xff1a;uni-app&#xff0c;uni-app官网 俗语曰&#xff1a;授人以鱼不如授人以渔 原创地址&#xff1a;Android制作.9图 语雀 一.工具 使用android studio&#xff0c;因为android studio已经集成.9.png制作工具&a…

某勾求职网逆向分析

搜索目标: aHR0cHM6Ly93d3cubGFnb3UuY29tL3duL2pvYnM/cG49MSZweD1kZWZhdWx0JmZyb21TZWFyY2g9dHJ1ZSZrZD0lRTYlOTUlQjAlRTYlOEQlQUUlRTUlODglODYlRTYlOUUlOTA= 抓包分析 请求和返回都是加密的 请求头部也有未知参数 跟栈分析 请求和返回是一个AES加密,加密的KEY是session s…

鸿蒙OS开发:典型页面场景【一次开发,多端部署】(信息应用)案例

信息应用 简介 内容介绍 Mms应用是OpenHarmony中预置的系统应用&#xff0c;主要的功能包含信息查看、发送短信、接收短信、短信送达报告、删除短信等功能。 架构图 目录 /Mms/ ├── doc # 资料 ├── entry │ └── src │…

springboot3项目练习详细步骤(第四部分:文件上传、登录优化、多环境开发)

目录 本地文件上传 接口文档 业务实现 登录优化 SpringBoot集成redis 实现令牌主动失效机制 多环境开发 本地文件上传 接口文档 业务实现 创建FileUploadController类并编写请求方法 RestController public class FileUploadController {PostMapping("/upload&…

Flink 通过 paimon 关联维表,内存降为原来的1/4

你好&#xff0c;我是 shengjk1&#xff0c;多年大厂经验&#xff0c;努力构建 通俗易懂的、好玩的编程语言教程。 欢迎关注&#xff01;你会有如下收益&#xff1a; 了解大厂经验拥有和大厂相匹配的技术等 希望看什么&#xff0c;评论或者私信告诉我&#xff01; 文章目录 一…

力扣62 不同路径 Java版本

文章目录 题目描述代码 题目描述 一个机器人位于一个 m x n 网格的左上角 &#xff08;起始点在下图中标记为 “Start” &#xff09;。 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角&#xff08;在下图中标记为 “Finish” &#xff09;。 问总共有多少…

C++笔试强训day35

目录 1.奇数位丢弃 2.求和 3.计算字符串的编辑距离 1.奇数位丢弃 链接https://www.nowcoder.com/practice/196141ecd6eb401da3111748d30e9141?tpId128&tqId33775&ru/exam/oj 数据量不大&#xff0c;可以直接进行模拟&#xff1a; #include <iostream> #incl…

06_知识点总结(JS高级)

一、进程与线程 1. 进程(process)&#xff1a;程序的一次执行, 它占有一片独有的内存空间 2. 线程(thread)&#xff1a; 是进程内的一个独立执行单元&#xff0c;CPU的基本调度单元, 是程序执行的一个完整流程 3. 进程与线程 * 应用程序必须运行在某个进程的某个线程上 * 一个…

曲线拟合工具软件(免费)

曲线拟合是数据处理中经常用到的数值方法,本质是使用某一个模型(方程或者方程组)将一系列离散的数据拟合成平滑的曲线或者曲面,数值求解出对应的函数参数,大家可以利用MATLAB的曲线拟合工具箱也可以使用第三方的拟合软件,今天我们介绍Welsim免费的曲线拟合软件 1、MATLA…