go语言negroni包介绍

go语言negroni包介绍

前言

go语言很好地支持了网络编程,go 语言与web 框架相关的包有很多,本文主要介绍go语言的negroni包。

前置参考博客:HTTP 协议 与 golang web 应用服务
这篇文章中潘老师介绍了go web的基本使用。

下面我们来了解一下negroni包。

negroni包是什么

negroni包是go的一个第三方库,是为了方便使用 net/http 而设计的一个库,由于该包设计优雅,易于扩展,被广泛使用。

negroni官方地址:https://github.com/urfave/negroni

negroni官方中文文档:https://github.com/urfave/negroni/blob/master/translations/README_zh_CN.md

negroni包的使用见官方文档,官方文档的教程很详细,可读性也还可以。

negroni包源码分析

negroni包源码在github仓库中,可以从github上克隆下来或者通过go get命令获得。

negroni包的源码结构如下(使用tree命令获得):

.
├── CHANGELOG.md
├── LICENSE
├── README.md
├── doc.go
├── go.mod
├── logger.go
├── logger_test.go
├── negroni.go
├── negroni_bench_test.go
├── negroni_test.go
├── recovery.go
├── recovery_test.go
├── response_writer.go
├── response_writer_pusher.go
├── response_writer_pusher_test
├── response_writer_test.go
├── static.go
├── static_test.go
└── translations
    ├── README_de_de.md
    ├── README_fr_FR.md
    ├── README_ja_JP.md
    ├── README_ko_KR.md
    ├── README_pt_br.md
    ├── README_zh_CN.md
    └── README_zh_tw.md

1 directory, 25 files

源码中真正起作用的只有logger.go、negroni.go、recovery.go、response_writer.go、response_writer_pusher.go、static.go共六个文件,其余都是文档和测试代码。
这六个文件的大小加起来只有18.8k,由此可见negroni包的小而精。

本文只对negroni.go这个文件进行分析,有兴趣的话可以自己看源码。
negroni.go这个文件只有不到两百行,定义了negroni包的接口。

我们来逐行分析negroni.go的程序。

// Handler handler is an interface that objects can implement to be registered to serve as middleware
// in the Negroni middleware stack.
// ServeHTTP should yield to the next middleware in the chain by invoking the next http.HandlerFunc
// passed in.
//
// If the Handler writes to the ResponseWriter, the next http.HandlerFunc should not be invoked.
type Handler interface {
	ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc)
}

// HandlerFunc is an adapter to allow the use of ordinary functions as Negroni handlers.
// If f is a function with the appropriate signature, HandlerFunc(f) is a Handler object that calls f.
type HandlerFunc func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc)

func (h HandlerFunc) ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
	h(rw, r, next)
}

首先是对Handler接口的定义,Handler接口要求实现ServeHTTP函数,参数类型是回复的写出流http.ResponseWriter、请求http.Request、回调函数http.HandlerFunc,
然后是对HandlerFunc的函数类型的定义,HandlerFunc的函数参数和Handler.ServeHTTP一致,都是回复、请求和回调函数三个参数。HandlerFunc是一个适配器,用于将外界的函数转化为能够被Negroni处理的类型。
然后定义HandlerFunc实现了ServeHTTP的虚函数,所以HandlerFunc可以转为Handler类型。

type middleware struct {
	handler Handler

	// nextfn stores the next.ServeHTTP to reduce memory allocate
	nextfn func(rw http.ResponseWriter, r *http.Request)
}

func newMiddleware(handler Handler, next *middleware) middleware {
	return middleware{
		handler: handler,
		nextfn:  next.ServeHTTP,
	}
}

func (m middleware) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
	m.handler.ServeHTTP(rw, r, m.nextfn)
}

接下来是中间件middleware的类型定义,可见中间件类型包括了一个Handler和一个回调函数,middleware包含回调函数的目的是减少内存的分配。
middleware实现了net/http里定义的ServeHTTP接口,通过调用middleware的handler的ServeHTTP来实现,这里形成了Negroni与原生的net/http包的无缝衔接。


// Wrap converts a http.Handler into a negroni.Handler so it can be used as a Negroni
// middleware. The next http.HandlerFunc is automatically called after the Handler
// is executed.
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)
	})
}

// WrapFunc converts a http.HandlerFunc into a negroni.Handler so it can be used as a Negroni
// middleware. The next http.HandlerFunc is automatically called after the Handler
// is executed.
func WrapFunc(handlerFunc http.HandlerFunc) Handler {
	return HandlerFunc(func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
		handlerFunc(rw, r)
		next(rw, r)
	})
}

接下来是定义装饰器,Wrap将http.Handler转换为一个negroni.Handler,WrapFunc将http.HandlerFunc转换为一个negroni.Handler,这里也是为了实现Negroni与原生的net/http包的无缝衔接。

// Negroni is a stack of Middleware Handlers that can be invoked as an http.Handler.
// Negroni middleware is evaluated in the order that they are added to the stack using
// the Use and UseHandler methods.
type Negroni struct {
	middleware middleware
	handlers   []Handler
}

// New returns a new Negroni instance with no middleware preconfigured.
func New(handlers ...Handler) *Negroni {
	return &Negroni{
		handlers:   handlers,
		middleware: build(handlers),
	}
}

// With returns a new Negroni instance that is a combination of the negroni
// receiver's handlers and the provided handlers.
func (n *Negroni) With(handlers ...Handler) *Negroni {
	currentHandlers := make([]Handler, len(n.handlers))
	copy(currentHandlers, n.handlers)
	return New(
		append(currentHandlers, handlers...)...,
	)
}

// Classic returns a new Negroni instance with the default middleware already
// in the stack.
//
// Recovery - Panic Recovery Middleware
// Logger - Request/Response Logging
// Static - Static File Serving
func Classic() *Negroni {
	return New(NewRecovery(), NewLogger(), NewStatic(http.Dir("public")))
}

再接下来是Negroni结构的定义以及构造函数,Negroni定义为一个middleware和一个handlers数组组成的结构体
Negroni的构造方法有三个:

  1. New,通过给出一系列的handler来构造Negroni,不定参数handlers组成Negroni的handlers数组,middleware通过辅助函数build来通过这一系列handler构造
  2. With,With通过一个已有的Negroni,并给出不定参数handlers,将给出的handlers附加到已有的Negroni的handlers后即可得到新的Negroni。
  3. Classic, Classic通过在栈中的默认的中间件构造,使用了Recovery、Logger、Static来给出保存的信息。
func (n *Negroni) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
	n.middleware.ServeHTTP(NewResponseWriter(rw), r)
}

// Use adds a Handler onto the middleware stack. Handlers are invoked in the order they are added to a Negroni.
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)
}

// UseFunc adds a Negroni-style handler function onto the middleware stack.
func (n *Negroni) UseFunc(handlerFunc func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc)) {
	n.Use(HandlerFunc(handlerFunc))
}

// UseHandler adds a http.Handler onto the middleware stack. Handlers are invoked in the order they are added to a Negroni.
func (n *Negroni) UseHandler(handler http.Handler) {
	n.Use(Wrap(handler))
}

// UseHandlerFunc adds a http.HandlerFunc-style handler function onto the middleware stack.
func (n *Negroni) UseHandlerFunc(handlerFunc func(rw http.ResponseWriter, r *http.Request)) {
	n.UseHandler(http.HandlerFunc(handlerFunc))
}

// Run is a convenience function that runs the negroni stack as an HTTP
// server. The addr string, if provided, takes the same format as http.ListenAndServe.
// If no address is provided but the PORT environment variable is set, the PORT value is used.
// If neither is provided, the address' value will equal the DefaultAddress constant.
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实现的接口和定义的成员函数。

余下部分是辅助函数。

结语

Negroni设计巧妙,用了适配器等设计模式,思想内涵丰富,需要学习的话可以自己阅读源码来深入研究。

你可能感兴趣的:(服务计算)