首页 > 其他分享 >Mygin实现中间件Middleware

Mygin实现中间件Middleware

时间:2024-01-26 16:57:37浏览次数:22  
标签:index Context mygin Middleware handlers 中间件 Mygin func

本篇是mygin的第六篇,参照gin框架,感兴趣的可以从 Mygin第一篇 开始看,Mygin从零开始完全手写,在实现的同时,带你一窥gin框架的核心原理实现。

目的

  • 实现中间件Middleware
    在上一篇 Mygin实现分组路由Group 中,实现了路由分组,且同一分组的执行,会先执行Group,有一点点中间件的雏形了。但是中间件不完全还应该提供中断功能,比如一个Group组中添加了auth鉴权中间件,只有auth认证通过才可以通过,因此需要对上篇中的内容进行一些修改。
    在实现之前,先分析gin中是怎样去实现的这一功能的
func (c *Context) Next() {
	c.index++
    //遍历handlers
	for c.index < int8(len(c.handlers)) {
        //真正调用执行handler方法
		c.handlers[c.index](c)
		c.index++
	}
}

这个时候就有疑问了,从上述方法中看不到中间件执行失败的中断方法,那又是怎么实现中断。
在揭晓答案之前,先看看int8(len(c.handlers) 为什么要写个int8,原因在于gin中规定的handlers最多63个,相信实际的应用请求中,没有超过63个那么多变态的执行链。在gin中如果某一中间件执行失败,就把c.index赋值为63,上述for循环就不满足条件,因此就跳出for循环,不再继续执行后面的代码。gin中对应的代码也很简单。

const abortIndex int8 = math.MaxInt8 >> 1
//中间件执行失败,中断方法
func (c *Context) Abort() {
	c.index = abortIndex
}

因此只需在mygin/content.go中新加Next方法和Abort方法

上下文

content.go中的代码不多,索性加上注释全部贴出来。

  • mygin/content.go
package mygin

import (
	"encoding/json"
	"math"
	"net/http"
)

// 定义 表示最大和上下文应中止时的索引值
const abortIndex int8 = math.MaxInt8 >> 1

// Context 封装了一个HTTP请求的上下文
type Context struct {
	Request *http.Request
	Writer  http.ResponseWriter
	Params  Params
	index   int8
}

// Next 执行链中的剩余处理程序。
func (c *Context) Next(handlers HandlersChain) {
	//遍历handlers
	for c.index < int8(len(handlers)) {
		//真正调用执行handler方法
		handlers[c.index](c)
		c.index++
	}
}

// Abort 中断链中剩余处理程序的执行。
func (c *Context) Abort() {
	c.index = abortIndex
}

// IsAborted 如果当前上下文被中止,则返回true。
func (c *Context) IsAborted() bool {
	return c.index >= abortIndex
}

// writeContentType 如果尚未设置,则设置Content-Type标头。
func writeContentType(w http.ResponseWriter, value []string) {
	header := w.Header()
	if val := header["Content-Type"]; len(val) == 0 {
		header["Content-Type"] = value
	}

}

// Status 设置HTTP响应状态码。
func (c *Context) Status(code int) {
	c.Writer.WriteHeader(code)
}

// JSON 将值序列化为JSON并将其写入响应。
func (c *Context) JSON(v interface{}) error {
	writeContentType(c.Writer, []string{"application/json; charset=utf-8"})
	encoder := json.NewEncoder(c.Writer)
	err := encoder.Encode(v)
	if err != nil {
		c.Status(http.StatusInternalServerError)
	}
	c.Status(http.StatusOK)
	return err
}

// Html 将字符串以HTML形式写入响应。
func (c *Context) Html(v string) error {
	writeContentType(c.Writer, []string{"text/html; charset=utf-8"})
	c.Status(http.StatusOK)
	_, err := c.Writer.Write([]byte(v))
	return err
}

// String 将字符串写入响应
func (c *Context) String(v string) error {
	writeContentType(c.Writer, []string{"text/plain; charset=utf-8"})
	c.Status(http.StatusOK)
	_, err := c.Writer.Write([]byte(v))
	return err
}

接下来就是调用handles的修改了,原来的解决方法是直接循环调用,对应的代码如下:

for _, handler := range handlers {
		handler(&Context{
			Request: r,
			Writer:  w,
			Params:  params,
		})
	}

引擎

  • mygin/engine.go
    现在找到engine.go文件中将上面的代码替换为:
	//实例化一个下上文
	c := &Context{
		Request: r,
		Writer:  w,
		Params:  params,
	}
	// 执行处理函数链
	c.Next(handlers)

测试代码

package main

import (
	"gophp/mygin"
	"path"
)

func main() {
	// 创建一个默认的 mygin 实例
	r := mygin.Default()

	//测试Abort
	group := r.Group("/api", func(context *mygin.Context) {
		//todo....
		context.String("api Group 中间件失败了....\n")
		context.Abort()
	})
	//这个回调不会执行
	group.GET("/hello/:name", func(context *mygin.Context) {
		name := context.Params.ByName("name")
		context.String(path.Join("hello ", name, "!"))
	})

	//测试没有发生Abort
	group2 := r.Group("/api2", func(context *mygin.Context) {
		//todo....
		context.String("api Group 中间件成功了....\n")
	})
	
	//这个回调会执行
	group2.GET("/hello2/:name", func(context *mygin.Context) {
		name := context.Params.ByName("name")
		context.String(path.Join("hello2 ", name, "!\n"))
	})

	// 启动服务器并监听端口
	r.Run(":8088")
}

curl测试

 curl http://127.0.0.1:8088/api/hello/scott
api Group 中间件失败了....
~ curl http://127.0.0.1:8088/api2/hello2/scott
api Group 中间件成功了....
hello2 /scott/!

看到上诉输出,即为成功。

标签:index,Context,mygin,Middleware,handlers,中间件,Mygin,func
From: https://www.cnblogs.com/pengb/p/17984996

相关文章

  • 名词解析——中间件
    操作系统、数据库、中间件号称系统软件三驾马车,其中的中间件是最神秘的。操作系统,如Windows,Linux等等,略有常识的小伙伴都耳熟能详,对于其功能也略知一二,数据库大致也许是一个用来存储数据的仓库。本文我们来简单的说一下中间件关于中间件:中间件是一种独立的系统软件或服务程序,分布......
  • 系统、中间件系统加固
    安全加固与应急响应Linux操作系统加固主要根据六个方面进行系统加固​ 版本升级、关闭端口服务、修改配置项(系统加固主要操作在此)、修改代码、主机和网络的ACL策略、部署设备防护安全加固测试流程回退测试——>业务测试——>有效性测试Linux系统加固实施案例:加固方向:......
  • Mygin实现分组路由Group
    本篇是Mygin第五篇目的实现路由分组为什么要分组分组控制(GroupControl)是Web框架应该提供的基础功能之一,对同一模块功能的开发,应该有相同的前缀。或者对一部分第三方接口,统一需要加解密等功能。分组后很方便。例如:对于任务模块,统一前缀为/task除去/user/login接口,都......
  • Mygin实现动态路由
    本篇是Mygin的第四篇目的使用Trie树实现动态路由解析。参数绑定前缀树本篇比前几篇要复杂一点,原来的路由是用map实现,索引非常高效,但是有一个弊端,键值对的存储的方式,只能用来索引静态路由。遇到类似hello/:name这动态路由就无能为力了,实现动态路由最常用的数据结构,被称为......
  • 使用Go编写HTTP中间件
    在Go语言中,HTTP中间件是一种处理HTTP请求和响应的函数,它可以拦截到请求并对其进行处理,然后再将请求传递给下一个中间件或目标处理程序。HTTP中间件在Web应用程序中非常常见,它提供了一种机制来执行各种任务,例如身份验证、授权、日志记录和错误处理等。下面是一个使用Go编写HTTP中间......
  • Go在Gin中解决CORS中间件没生效的问题
    起因最近在写前后端分离项目,然后在前端访问后端提供的接口时,会出现CORS问题。查找资料发现,Gin官方是有提供中间件的https://github.com/gin-contrib/cors先在terminal输入gogetgithub.com/gin-contrib/cors然后就按照官方的使用例子就行:packagemainimport("time"......
  • 中间件 ZK分布式专题与Dubbo微服务入门 4-15 acl的常用使用场景
    0课程地址https://coding.imooc.com/lesson/201.html#mid=12711 1重点关注1.1zk集群,主从节点,心跳机制(选举模式) 选举模式介绍1xx主节点(主人),yy和zz从节点(奴隶)2xx主节点挂掉了,yy和zz竞争当主人,结果zz成功上位,zz是主节点,yy是从节......
  • 削峰填谷与应用间解耦:分布式消息中间件在分布式环境下并发流量控制的应用
    这是《百图解码支付系统设计与实现》专栏系列文章中的第(18)篇,也是流量控制系列的第(4)篇。点击上方关注,深入了解支付系统的方方面面。本篇重点讲清楚分布式消息中间件的特点,常见消息中间件的简单对比,在支付系统的应用场景,比如削峰填谷,系统应用间的解耦,事务消息等。内容偏入门介绍,已经......
  • .net 温故知新【17】:Asp.Net Core WebAPI 中间件
    一、前言到这篇文章为止,关于.NET"温故知新"系列的基础知识就完结了,从这一系列的系统回顾和再学习,对于.NETcore、ASP.NETCORE又有了一个新的认识。不光是从使用,还包括这些知识点的原理,虽然深入原理谈不上,但对于日常使用也够了,我想的是知其然,知其所以然。在实际开发过程中可能......
  • C# 自定义日志中间件 ASP.NET Core Web API
    自定义日志中间件usingMicrosoft.AspNetCore.Builder;usingMicrosoft.AspNetCore.Http;usingMicrosoft.AspNetCore.Http.Extensions;usingMicrosoft.Extensions.DependencyInjection;usingMicrosoft.Extensions.Logging;usingNewtonsoft.Json;usingSystem;usingS......