本篇是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. CWE4.6标准中加入 OWASP 2021 TOP10

    摘要: 新发布的CWE4.6标准,加入了OWASP 2021 TOP10的视图. 本文分享自华为云社区<CWE 4.6 和 OWAPS TOP10(2021)>,作者: Uncle_Tom ...

  2. 2023年iOS App Store上架流程详解(上)

    ​ 很多开发者在开发完iOS APP.进行内测后,下一步就面临上架App Store,不过也有很多同学对APP上架App Store的流程不太了解,下面我们来说一下iOS APP上架App Store ...

  3. ORM之Sequelize

    一.环境: Vue.Quasar.Electron.Postgres.Sequelize.sequelize-auto 二.安装 (1)添加Sequelize(全局安装) $npm install - ...

  4. 【每日一题】7.月月查华华的手机 (枚举 or 序列自动机)

    题目链接:Here 题意总结:\(N\) 次查询串 \(B\) 是否是 \(A\) 的子序列. 思路一 个人做法,枚举原字符串的每一位,如果匹配当前字符串的字符则 m++ 直到字符串枚举完毕或者 m ...

  5. 【体验有奖】使用 Serverless 1 步搭建照片平台!

    实验介绍 当前,Serverless 技术已经被广泛应用,Serverless = FaaS + BssS 的概念已经深入人心.本场景由函数计算和 RDS MySQL Serverless 联合打造, ...

  6. S3C2440移植uboot之新建单板_时钟_SDRAM_串口

    上一节S3C2440移植uboot之启动过程概述我们我们分析了uboot启动流程,这节将开始新建一块单板支持S3C2440. 目录 1.新建单板 1.1 将2410的单板文件夹拷贝成2440: 1.2 ...

  7. location对象的方法

    location.assign() 跟href一样,可以跳转页面(也称为重定向页面). location.replace() 替换当前页面,因为不记录历史,所以不能后退页面. location.rel ...

  8. C#设计模式09——组合模式的写法

    1. 什么是C#组合模式? 组合模式是一种结构型设计模式,它允许将对象组合成树形结构以表示"整体/部分"层次结构.使用此模式,客户端可以按相同的方式处理单个对象和对象集合,而不必关 ...

  9. 一文搞清楚Java中的方法、常量、变量、参数

    写在开头 在上一篇文章:一文搞清楚Java中的包.类.接口 中我们讲了Java中的包.类和接口,今天继续将剩下的方法.常量.变量以及参数梳理完. Java中的变量与常量 在JVM的运转中,承载的是数据 ...

  10. 【rt-thread】Kconfig文件添加子Kconfig文件时是以顶级Kconfig所在目录为当前路径的

    示例如下 顶级Kconfig文件所在目录 子级Kconfig文件所在目录 子级Kconfig文件添加次子级Kconfig文件,以顶级目录为当前路径依次写出次子级Kconfig文件所在目录