手把手和你一起实现一个Web框架实战——EzWeb框架(五)[Go语言笔记]Go项目实战

代码仓库:

github

gitee

中文注释,非常详尽,可以配合食用

本篇代码,请选择demo5

中间件实现

一、Context设计

type Context struct {
Writer http.ResponseWriter
Req *http.Request
//请求的信息,包括路由和方法
Path string
Method string
Params map[string]string /*用于存储外面拿到的参数 ":xxx" or "*xxx" */
//响应的状态码
StatusCode int
//中间件
handlers []HandlerFunc
index int /* 用于记录当前执行到第几个中间件 */
}

我们每次请求生成的context,我们选择在其中放入和我们中间件和执行控制变量index

二、中间件对路由组的注册方法

// 将路中间件,放入路由组的中间件方法切片中
func (group *RouterGroup) Use(middlewares ...HandlerFunc) {
group.middlewares = append(group.middlewares, middlewares...)
}

当每个请求到来后,ServeHTTP函数执行时,它将该生成一个context并将进行传入的url和路由组前缀做前缀对比,找到满足条件的路由组,取出它的中间件,然后存入到生成的context。

// ServeHTTP 方法的实现,用于实现处理HTTP请求
func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) {
var middlewares []HandlerFunc
for _, group := range engine.groups {
//比对路由组存的前缀和请求路径,把属于这个请求映射的路由组中的中间件取到
//意思就是比对发现该请求属于哪一个路由组,需要哪些中间件,取出来执行
if strings.HasPrefix(req.URL.Path, group.prefix) {
middlewares = append(middlewares, group.middlewares...)
}
}
//根据req和w实例一个context
c := newContext(w, req)
//将取道的中间件赋给这个context
c.handlers = middlewares
//通过封装好的context执行处理
engine.router.handle(c)
}

三、处理函数

在处理函数handle()中,我们根据路由拿到已经注册的方法,放入到中间件后,在通过Next函数进行处理

//根据context中存储的 c.Method 和 c.Path 拿到对应的处理方法,进行执行,如果拿到的路由没有注册,则返回404
func (r *router) handle(c *Context) {
//获取匹配到的节点,同时也拿到两类动态路由中参数
n, params := r.getRoute(c.Method, c.Path)
if n != nil {
c.Params = params
//拿目的节点中的path做key来找handlers
key := c.Method + "-" + n.path
//根据路径拿到处理器
c.handlers = append(c.handlers, r.handlers[key])
}else {
//不存在节点的情况下,给生成的c加入一个404方法
c.handlers = append(c.handlers, func(c *Context) {
c.String(http.StatusNotFound, "404 NOT FOUND: ", c.Path)
})
}
c.Next()
}

四、Next方法执行处理

index进行控制,遍历完c.handlers中存储的方法执行。

// 当中间件调用了 Next 方法时,就往后执行下一个,同时index交由下一个中间件控制
func (c *Context) Next() {
c.index++
//执行完之后所有的handlers
for ;c.index < len(c.handlers); c.index++{
c.handlers[c.index](c)
}
}

这里的日志中间件在Next中被执行时,也调用了Next函数。这里第四行的执行巧妙的做到了,控制index++,执行下一个中间件,直到执行完了又回到Logger执行,回到原来的Next的for循环,发现不满足继续循环的条件,然后退出。

func Logger() HandlerFunc {
return func(c *Context) {
t := time.Now()
c.Next()
log.Printf("[%d] %s in %v", c.StatusCode, c.Req.RequestURI, time.Since(t))
}
}

demo测试:

/*
@Time : 2021/8/16 下午4:01
@Author : mrxuexi
@File : main
@Software: GoLand
*/
package main import (
"Ez"
"net/http"
)
func main() {
r := Ez.New()
//给所有的路由组都添加了中间件logger
r.Use(Ez.Logger())
api := r.Group("/api") api.POST("/hello", func(c *Ez.Context) {
c.JSON(http.StatusOK,Ez.H{
"message" : "hello",
})
})
//next的应用
api.Use(func(c *Ez.Context) {
c.JSON(200,Ez.H{
"test" : "middleware2-1",
})
c.Next()
c.JSON(200, Ez.H{
"test" : "middleware2-2",
})
}) r.Run(":9090")
}

成功!

参考:

[1]: https://github.com/geektutu/7days-golang/tree/master/gee-web ""gee""

[2]: https://github.com/gin-gonic/gin ""gin""

手把手和你一起实现一个Web框架实战——EzWeb框架(五)[Go语言笔记]Go项目实战的更多相关文章

  1. 手把手和你一起实现一个Web框架实战——EzWeb框架(二)[Go语言笔记]Go项目实战

    手把手和你一起实现一个Web框架实战--EzWeb框架(二)[Go语言笔记]Go项目实战 代码仓库: github gitee 中文注释,非常详尽,可以配合食用 上一篇文章我们实现了框架的雏形,基本地 ...

  2. 手把手和你一起实现一个Web框架实战——EzWeb框架(三)[Go语言笔记]Go项目实战

    手把手和你一起实现一个Web框架实战--EzWeb框架(三)[Go语言笔记]Go项目实战 代码仓库: github gitee 中文注释,非常详尽,可以配合食用 本篇代码,请选择demo3 这一篇文章 ...

  3. 手把手和你一起实现一个Web框架实战——EzWeb框架(四)[Go语言笔记]Go项目实战

    手把手和你一起实现一个Web框架实战--EzWeb框架(四)[Go语言笔记]Go项目实战 代码仓库: github gitee 中文注释,非常详尽,可以配合食用 这一篇文章主要实现路由组功能.实现路由 ...

  4. Go语言笔记[实现一个Web框架实战]——EzWeb框架(一)

    Go语言笔记[实现一个Web框架实战]--EzWeb框架(一) 一.Golang中的net/http标准库如何处理一个请求 func main() { http.HandleFunc("/& ...

  5. 用C写一个web服务器(三) Linux下用GCC进行项目编译

    .container { margin-right: auto; margin-left: auto; padding-left: 15px; padding-right: 15px } .conta ...

  6. Python之路,Day18 - 开发一个WEB聊天来撩妹吧

    Python之路,Day18 - 开发一个WEB聊天来撩妹吧   本节内容: 项目实战:开发一个WEB聊天室 功能需求: 用户可以与好友一对一聊天 可以搜索.添加某人为好友 用户可以搜索和添加群 每个 ...

  7. 【转载】ASP.NET MVC Web API 学习笔记---第一个Web API程序

    1. Web API简单说明 近来很多大型的平台都公开了Web API.比如百度地图 Web API,做过地图相关的人都熟悉.公开服务这种方式可以使它易于与各种各样的设备和客户端平台集成功能,以及通过 ...

  8. ASP.NET MVC Web API 学习笔记---第一个Web API程序

    http://www.cnblogs.com/qingyuan/archive/2012/10/12/2720824.html GetListAll /api/Contact GetListBySex ...

  9. ASP.NET MVC Web API 学习笔记---第一个Web API程序【转】

    http://www.cnblogs.com/qingyuan/archive/2012/10/12/2720824.html 1. Web API简单说明 近来很多大型的平台都公开了Web API. ...

随机推荐

  1. redis集群环境配置

    为什么需要集群 redis是一个开源的 key->value 高速存储系统,但是由于redis单线程运行,在系统中,只能利用单核的性能 当redis的调用越来越频繁时,可能会出现redis过于繁 ...

  2. 第四章 python的turtle库的运用

    我们可以尝试用python的自带turtle库绘制一条蟒蛇 首先我们设计一下蟒蛇的基本形状 我们先把这段蟒蛇绘制的实例代码贴出来,各位可以在自己的本地运行一下看看效果,然后我们再继续分析代码: 1 # ...

  3. netcore3.1 + vue (前后端分离)生成PDF(多pdf合并)返回前端打印

    1.使用Adobe Acrobat XI Pro编辑pdf模板 2.公共类代码 3.service层调用 4.Controller层 5.前端(Vue) 因为print.js不支持宋体,所以打算用后台 ...

  4. Linux常用命令 day day up系列3

    一.命令执行的优先级二.Linux目录结构三.cat--查看文件内容四.more--查看文件内容五.less--查看文件内容六.head.tail--查看文件内容七.wc--统计文件内容八.grep- ...

  5. EXCEL:宏 考场考号打印

    Sub addwork() Rem 当前宏是根据学生数量 .每考场人数计算工作表数Dim i As IntegerRem xx为每个考场的人数Rem yy为当前专业标记Rem mm为当前专业考生人数R ...

  6. HTML表单__表单元素属性

    看完"HTML表单__表单元素"那一节的同学会发现,同是input标签,type属性值不一样的时候,input类型完全不一样.type就是input的一个属性,除type之外,还有 ...

  7. [刘阳Java]_Java基础面试中的常识问题

    1. anonymous inner class(匿名内部类)是否可以extends(继承)其它类,是否可以implements(实现)interface(接口)? 不行,对于匿名内部类,看到的一句话 ...

  8. 单细胞分析实录(17): 非负矩阵分解(NMF)代码演示

    本次演示使用的数据来自2017年发表于Cell的头颈鳞癌单细胞文章:Single-Cell Transcriptomic Analysis of Primary and Metastatic Tumo ...

  9. 解决proto文件生成pb文件时提示(e.g."message")的问题

    原因:格式不支持 解决办法:去下个notepad,打开方式选择notepad,文件属性的只读取消掉 打开后会发现最下面显示了文件的格式是unix,utf-8 右键红框处,选择转换为windows格式, ...

  10. linux服务器环境部署(三、docker部署nginx)

    一.下载nginx镜像 官网地址:https://hub.docker.com/_/nginx #下载镜像 默认为最新版本 docker pull nginx#下载指定版本 docker pull n ...