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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

小熊家务帮day5 客户管理模块1 (小程序认证,手机验证码认证等)

客户管理模块 1.认证模块1.1 认证方式介绍1.1.1 小程序认证1.1.2 手机验证码登录1.1.3 账号密码认证 1.2 小程序认证1.2.1 小程序申请1.2.2 创建客户后端工程jzo2o-customer1.2.3 开发部署前端1.2.4 小程序认证流程1.2.4.1 customer小程序认证接口设计Controller层Service层调用…

使用Spring Boot编写的小项目

加法计算器 前端代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title> <…

杭州威雅学校:在学业与生活平衡中找到更好的自己

进入威雅杭州校园&#xff0c; 沿湖边小道步行约5分钟&#xff0c; 四栋寄宿学院与教学区隔湖相望&#xff0c; 威雅人更喜欢叫他们&#xff1a; 「Cavell」&「Dove」 「Elgar」&「Hawking」 提起「寄宿制」&#xff0c;人们本能地会把它和「住校」划等号。 这种…

【官方指南】3ds Max中纹理贴图问题及正确解决方案

在使用3ds Max进行设计和制作时&#xff0c;纹理贴图是一个非常重要的环节。然而&#xff0c;许多用户在使用过程中常会遇到各种纹理贴图问题。为此&#xff0c;Autodesk官方提供了一些有效的解决方案&#xff0c;可以解决90%的纹理贴图难题。这里小编都帮大家整理好了&#xf…

【加密与解密(第四版)】第十二章笔记

第十二章 注入技术 12.1 DLL注入方法 在通常情况下&#xff0c;程序加载 DLL的时机主要有以下3个&#xff1a;一是在进程创建阶段加载输入表中的DLL&#xff0c;即俗称的“静态输人”;二是通过调用 LoadLibrary(Ex)主动加载&#xff0c;称为“动态加载”&#xff1b;三是由于系…

网络原理-------TCP协议

文章目录 TCP协议TCP协议段格式TCP原理确认应答机制 (安全机制)超时重传机制 (安全机制)连接管理机制 (安全机制)滑动窗口 (效率机制)流量控制 (安全机制)拥塞控制 (安全机制)延迟应答 (效率机制)捎带应答 (效率机制) 基于TCP的应用层协议 TCP协议 TCP, 即 Transmission Contr…

The Sandbox DAO:投票决定元宇宙的未来!

赋予用户治理权&#xff0c;打造由社群运营的开放式数码国度 随着The Sandbox DAO的启动&#xff0c;我们邀请全球社群——这个新数字国度的公民们——提出建议并参与治理&#xff0c;共同塑造开放元宇宙的未来。 介绍 在The Sandbox&#xff0c;我们正在建立一个开放的元宇宙…

数据恢复与取证软件: WinHex 与 X-Ways Forensics 不同许可证功能区别

天津鸿萌科贸发展有限公司从事数据安全业务20余年&#xff0c;在数据恢复、数据取证、数据备份等领域有丰富的案例经验、专业技术及良好的行业口碑。同时&#xff0c;公司面向取证机构及数据恢复公司&#xff0c;提供数据恢复实验室建设方案&#xff0c;包含数据恢复硬件设备及…

【C++初阶】--- C++入门(中)

目录 一、缺省参数1.1 缺省参数概念1.2 缺省参数分类 二、函数重载2.1 函数重载概念2.2 C支持函数重载的原理 --- 名字修饰 三、引用3.1 引用概念3.2 引用特性3.3 常引用3.4 使用场景3.5 引用和指针的区别 一、缺省参数 1.1 缺省参数概念 缺省参数是声明或定义函数时为函数的…

003 仿muduo实现高性能服务器组件_前置知识

​&#x1f308;个人主页&#xff1a;Fan_558 &#x1f525; 系列专栏&#xff1a;仿muduo &#x1f339;关注我&#x1f4aa;&#x1f3fb;带你学更多知识 文章目录 前言时间轮timewheel设计正则表达式介绍&#xff08;了解知道怎么使用&#xff09;通用型any容器的实现 小结 …

5-26作业

网络聊天室 服务器&#xff1a; 1 #include <myhead.h>2 int main(int argc, const char *argv[])3 {4 if(argc!3)5 {6 printf("请输入IP和端口号\n");7 return -1;8 }9 int sfd socket(AF_INET, SOCK_DGRAM, 0);10 if(…

6千古诗文必背名句大全ACCESS\EXCEL数据库

古诗&#xff0c;是古代诗歌的一种体裁&#xff0c;又称古体诗或古风&#xff0c;指的是产生于唐代以前并和唐代新出现的近体诗&#xff08;又名今体诗&#xff09;相对的一种诗歌体裁。其特点是格律限制不太严格。 从小我们就被教“熟读唐诗三百首,不会吟诗也会吟”&#xff…

男士内裤什么品牌质量好?男内裤品牌排行榜汇总

大家都知道&#xff0c;为了私处健康&#xff0c;每天都必须换内裤。而且&#xff0c;使用频率较高的内裤最好 3&#xff5e;6 个月换一批&#xff0c;一旦变形、材质变干硬或污渍洗不净&#xff0c;就得及时扔&#xff01;但有一说一&#xff0c;现在男性同胞们想挑选到合适自…

MySQL数据表的“增删查改“

我们学习数据库, 最重要的就是要学会对数据表表进行"增删查改"(CRUD).(C -- create, R -- retrieve, U -- update, D -- delete) 目录 一. "增"(create) 1. 普通新增 2. 指定列新增 3. 一次插入多行 4. 用insert插入时间 5. 小结 二. "查"…

css样式,点击 箭头方向上下转换

实现效果&#xff1a; 点击切换箭头方向 实现代码 <divclass"modelPart"click"showClick"><div class"modelPart_left"><img:srcaidefalutIconclass"sNodeIcon"><div>{{ selectModel }}</div><div …

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

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

【edge浏览器】控制台报错信息隐藏-恢复

问题描述 解决方法&#xff1a;只需要清空筛选器

进程和用户管理

查看进程的命令 ps top pstree 发送信号命令 kill 使用是后加-l 用户管理命令 添加用户:sudo adduser 用户名 修改组:sudo usermod -G 用户名1 用户名2 修改家目录:sudo usermod -d /home/用户名 -m 用户名 删除用户名:sudo deluser --remove -home 用户名

Java 使用WebMagic爬取网页(简单示例)

框架简介 WebMagic是一个基于Java的开源网络爬虫框架&#xff0c;它提供了很多简单易用的API接口&#xff0c;可以帮助使用者快速构建出高效、可扩展的网络爬虫程序&#xff0c;WebMagic由四个组件(Downloader、PageProcessor、Scheduler、Pipeline)构成&#xff0c;核心代码非…

GitHub打不开的解决方案

1、打开https://sites.ipaddress.com/github.com/找到DNS Resource Records&#xff0c;复制github的ip地址&#xff0c;先保存起来&#xff1a; 140.82.112.32、打开https://sites.ipaddress.com/fastly.net/找到DNS Resource Records&#xff0c;复制其中一个ip地址&#xf…