本篇是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/!

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

Mygin实现中间件Middleware的更多相关文章

  1. ASP.NET Core 开发-中间件(Middleware)

    ASP.NET Core开发,开发并使用中间件(Middleware). 中间件是被组装成一个应用程序管道来处理请求和响应的软件组件. 每个组件选择是否传递给管道中的下一个组件的请求,并能之前和下一组 ...

  2. ASP.NET Core中间件(Middleware)实现WCF SOAP服务端解析

    ASP.NET Core中间件(Middleware)进阶学习实现SOAP 解析. 本篇将介绍实现ASP.NET Core SOAP服务端解析,而不是ASP.NET Core整个WCF host. 因 ...

  3. laravel中间件-----------middleware

    middleware中间件 是访问到达服务器后在被对应的路由处理之前所经过的一层过滤层,故称中间件. 中间件是存放在app\http\middleware中,需要定一个 handle 处理方法,在ha ...

  4. 二、中间件(middleware)

    1.      中间件(middleware) Django中的中间件主要实现一些附加功能,在request被用户handler处理前,以及用户handler处理后生存的response进行处理.因此 ...

  5. 中间件(Middleware)

    中间件(Middleware) ASP.NET Core开发,开发并使用中间件(Middleware). 中间件是被组装成一个应用程序管道来处理请求和响应的软件组件. 每个组件选择是否传递给管道中的下 ...

  6. 初探中间件(middleware)

    初探中间件(middleware) 因为考虑到文章的长度, 所以 BaseHandler 的展开被推迟了. 在 BaseHandler 中隐藏着中间件的信息, 较常见的 SessionMiddlewa ...

  7. django中间件Middleware

    熟悉web开发的同学对hook钩子肯定不陌生,通过钩子可以方便的实现一些触发和回调,并且做一些过滤和拦截. django中的中间件(middleware)就是类似钩子的一种存在.下面我们来介绍一下,并 ...

  8. 如何传递参数给ASP.NET Core的中间件(Middleware)

    问题描述 当我们在ASP.NET Core中定义和使用中间件(Middleware)的时候,有什么好的办法可以给中间件传参数吗? 解决方案 在ASP.NET Core项目中添加一个POCO类来传递参数 ...

  9. ASP.NET Core -中间件(Middleware)使用

    ASP.NET Core开发,开发并使用中间件(Middleware). 中间件是被组装成一个应用程序管道来处理请求和响应的软件组件. 每个组件选择是否传递给管道中的下一个组件的请求,并能之前和下一组 ...

  10. C# Owin 创建与测试自己的中间件Middleware(二)

    本文纯属介绍怎么简单地创建自己的Owin.还没有理解owin概念的请看上一篇文章:http://www.cnblogs.com/alunchen/p/7049307.html 目录 1.创建项目 2. ...

随机推荐

  1. 技术架构+应用场景揭秘,为什么高斯Redis比开源香?

    摘要:高斯Redis即保留了开源Redis的能力,同时凭借其存算分离的架构,在成本.稳定性.可靠性.一致性等方面做出了新的突破,也更加适用于当下数据规模庞大的互联网业务. 本文分享自华为云社区< ...

  2. Chrome浏览器导出HTTPS证书

    点证书小锁 进入证书界面 到详情中,导出证书

  3. Sublime Json 格式化

    Ctrl+Shift+P 安装  pretty json  Ctrl+Alt+J

  4. Java 事件链

    Java中的事件机制的参与者有3种角色: 1. event object:就是事件产生时具体的"事件",用于listener的相应的方法之中,作为参数,一般存在于listerner ...

  5. 41. 干货系列从零用Rust编写负载均衡及代理,websocket与tcp的映射,WS与TCP互转

    wmproxy wmproxy已用Rust实现http/https代理, socks5代理, 反向代理, 静态文件服务器,四层TCP/UDP转发,七层负载均衡,内网穿透,后续将实现websocket代 ...

  6. auth认证模块 auth_user表扩展

    目录 auth认证模块前戏 django后台管理功能 创建超级管理员 auth认证相关模块及操作 用户注册 用户登录 网站首页效果 校验用户登录的装饰器 用户修改密码 用户注销登录 auth_user ...

  7. 用 three.js 绘制三维带箭头线 (线内箭头)

    在LineMaterial.js基础上修改的ArrowLineMaterial.js代码: /** * @author WestLangley / http://github.com/WestLang ...

  8. px2vw一个px单位转成vw单位的VSCode插件

    px2vw 一个 px 单位转成 vw 单位的 VSCode 插件

  9. C#查找算法1:二分查找

    二分查找也称折半查找(Binary Search),它是一种效率较高的查找方法.但是,折半查找要求线性表必须采用顺序存储结构,而且表中元素按关键字有序排列. 原理:将n个元素分成个数大致相同的两半,取 ...

  10. java基础-数组-day06

    1. 引入数组 录入10个学生的成绩 求和 求平均 import java.util.Scanner; public class TestArray01{ public static void mai ...