Negroni中间件源码分析
概述
我们可以先看一下HTTP Server的处理逻辑:
在这个逻辑处理的环节中,Negroni充当一个HTTP Handler的角色,并对于所有的HTTP Request的处理都会通过Negroni被转交到其内部的子中间件
实现Negroni
Negroni本质上可以被看作一个中间件是因为它实现了HTTP Handler接口,因此它可以被http.ListenAndServe()
调用:
func (n *Negroni) ServeHTTP(rw http.ResponseWriter, r *http.Request) {n.middleware.ServeHTTP(NewResponseWriter(rw), r)
}
而Negroni本身内部也具有自身的中间件,也就是标准库http调用中间件Negroni,然后Negroni调用自身的中间件来完成对各种HTTP Request的处理
这样设计的好处在于:对于HTTP Request来说,相当与有了一个统一的接口,所有的对HTTP Request的处理都会被转交到Negroni内部的子中间件进行处理,这样子Negroni相当与一个集线器的作用
子中间件的接口为:
type Handler interface {ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc)
}type HandlerFunc func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc)
Negroni自身的Handler定义与标准库http的定义非常相似,只是多了一个参数next
,这个参数使得Negroni的中间件形成链状结构
Negroni中间件链
上述我们提到Negroni对于HTTP Handler的实现的区别只在于多了一个参数next
,这是因为Negroni内部会维护一条Handler链,源码如下:
type Negroni struct {middleware middlewarehandlers []Handler
}func New(handlers ...Handler) *Negroni {return &Negroni{handlers: handlers,middleware: build(handlers),}
}func build(handlers []Handler) middleware {var next middlewareif len(handlers) == 0 {return voidMiddleware()} else if len(handlers) > 1 {next = build(handlers[1:])} else {next = voidMiddleware()}return middleware{handlers[0], &next}
}func Classic() *Negroni {return New(NewRecovery(), NewLogger(), NewStatic(http.Dir("public")))
}
其中build函数会递归创建一个类似链表结构的Handler链,结构如下:
初始化Negroni
我们可以调用Negroni.Classic()
函数来创建一个Negroni指针:
func Classic() *Negroni {return New(NewRecovery(), NewLogger(), NewStatic(http.Dir("public")))
}
然后Classic()
函数会调用New
函数来创建并初始化一个Negroni对象并将指针返回:
func New(handlers ...Handler) *Negroni {return &Negroni{handlers: handlers,middleware: build(handlers),}
}
在New
函数中,会将传入的handlers保存下来并传给build
方法,然后build
方法会按照上面所说的方式来构建一条Handler链
Negroni.UseHandler实现
我们可以用Negroni.UseHandler来实现我们自定义的Handler,源码如下:
func (n *Negroni) UseHandler(handler http.Handler) {n.Use(Wrap(handler))
}
方式是将传入的Handler进行一定的包装然后交给Use
函数处理:
func (n *Negroni) Use(handler Handler) {if handler == nil {panic("handler cannot be nil")}n.handlers = append(n.handlers, handler)n.middleware = build(n.handlers)
}
然后Use
函数再将包装过的Handler加在Handler链的末尾和放到一个数组中保存
其中包装函数Wrap
的实现为:
func Wrap(handler http.Handler) Handler {return HandlerFunc(func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {handler.ServeHTTP(rw, r)next(rw, r)})
}
因此UseHandler
函数本质上是将http.Handler
转换为negroni.handler
的过程
Negroni.Run实现
使用Negroni.Run函数可以运行我们的服务器,其源码为:
func (n *Negroni) Run(addr ...string) {l := log.New(os.Stdout, "[negroni] ", 0)finalAddr := detectAddress(addr...)l.Printf("listening on %s", finalAddr)l.Fatal(http.ListenAndServe(finalAddr, n))
}
在上文中也已经说过,Negroni本身也是一个Handler,因此可以直接被http.ListenAndServe
调用:
func (n *Negroni) ServeHTTP(rw http.ResponseWriter, r *http.Request) {n.middleware.ServeHTTP(NewResponseWriter(rw), r)
}
当http.ListenAndServe
调用Negroni.ServeHTTP接口方法时,其实是调用中间件的Handler实现的ServeHTTP接口方法:
func (m middleware) ServeHTTP(rw http.ResponseWriter, r *http.Request) {m.handler.ServeHTTP(rw, r, m.next.ServeHTTP)
}
因此Negroni的作用相当与一个集线器或者说Controller,将多个Handler统筹起来,让它们对于http.ListenAndServe
有一个统一的接口
Negroni中间件源码分析相关推荐
- golang学习之negroni/gizp源码分析
在 Go 语言里,Negroni 是一个很地道的 Web 中间件,它是一个具备微型.非嵌入式.鼓励使用原生 net/http 库特征的中间件.利用它地Use功能,我们可以很简单地自定义中间件并使用.其 ...
- 初识洋葱模型,分析中间件执行过程,浅析koa中间件源码
前言 作为洋葱模型的第一篇文章,这里仅介绍了一些入门级知识,比如 了解洋葱模型执行顺序 分析部分 koa 中间件的源码来加深对中间件的认识 为第二篇文章:分析洋葱模型实现原理,在自己项目中接入洋葱模型 ...
- Koa2和Redux中间件源码研究
一.Koa2中间件源码分析 在Koa2中,中间件被存放在一个数组中. 使用koa中,最常见的就是app.use(fn),use函数部分源码如下所示.首先中间件必须是个函数.若是generator函数, ...
- Django源码分析5:session会话中间件分析
django源码分析 本文环境python3.5.2,django1.10.x系列 1.这次分析django框架中的会话中间件. 2.会话保持是目前框架都支持的一个功能,因为http是无状态协议,无法 ...
- Django源码分析4:staticfiles静态文件处理中间件分析
django源码分析 本文环境python3.5.2,django1.10.x系列1.在上一篇文章中已经分析过handler的处理过程,其中load_middleware就是将配置的中间件进行初始化, ...
- 数据库中间件 MyCAT源码分析 —— XA分布式事务
title: MyCAT 源码分析 -- XA分布式事务 date: 2017-07-15 tags: categories: MyCAT permalink: MyCAT/xa-distribute ...
- koa2 一网打尽(基本使用,洋葱圈,中间件机制和模拟,源码分析,核心点,生态)
原文https://juejin.im/entry/5bfbe5a76fb9a049cb186cfa/detail koa homepage 优秀的下一代 web 开发框架. Koa 应用程序不是 H ...
- negroni-gzip源码分析
gibhub地址:针对negroni的gzip 作业内容:支持了gzip的服务器小程序 这是一个为Negroni设计的gzip压缩处理中间件,需要用到已有的compress中的gzip.源码共有一百多 ...
- 【Golang源码分析】Go Web常用程序包gorilla/mux的使用与源码简析
目录[阅读时间:约10分钟] 一.概述 二.对比: gorilla/mux与net/http DefaultServeMux 三.简单使用 四.源码简析 1.NewRouter函数 2.HandleF ...
最新文章
- Ubuntu 系统安装Visual Studio Code
- 只需一行代码,你的纯文本秒变 Markdown
- sm4 前后端 加密_这7个开源的Spring Boot前后端分离项目整理给你
- 记一次discuz修改首页图片路径问题
- 查看mysql半杯_如何通过show slave status的输出使用change master to命令 | 半瓶
- 计算机语言语法语义,程序设计语言语义
- php mysql 进销存_PHP进销存源码 仓库管理系统 WEB进销存 php+mysql 网络版进销存
- c语言case用多重语句,switch多重选择
- Eclipse中Folder和SourceFolder
- python绘制直线的垂线_Matplotlib:散点图中的垂直线
- Mobicomm 2019
- AutoFac在WinForm中的使用
- td自动换行时不切断英文单词
- QUIC构建1——chromium镜像,clone文件depot_tools的过程+git过程中的问题
- 苹果pencil值得买吗?苹果平板电容笔推荐
- C99:C标准库接口的头文件集和功能定义参考
- 企业 Apple 设备管理概述
- matlab 代码分析 内存溢出,matlab内存溢出的解决方案
- vs2008 的一些编译常识
- 计算机图形学教程答案,《计算机图形学教程》试卷A答案
热门文章
- 03 关键测量指标——整体网络测量
- 4 行代码写 3 个NPE异常,服了!
- springboot+Vue开发的 ktv预定管理系统
- vue -V 执行失败 檔案名稱、目錄名稱或磁碟區標籤語法錯誤。
- python应用——分治法实现循环赛
- 微信运动服务器多久同步一次,微信运动多久更新一次步数(微信运动刷新时间表)...
- 图片的居中定位和按钮定位
- cdr存成html格式的文件格式,CDR必备!CDR保存与各种格式之间转换!-cdr文件用什么打开...
- 复利计算计算器_C程序计算复利
- 语音与影像上的自督导式学习模型、一些老版本的补充(李宏毅2022