本文是构建 Go Web 框架的第二篇,目标是介绍中间件的最佳实践,访问原文。
译文如下:
在编写 Go Web 应用时,代码重复是大多数开发者将会遇到的第一个问题。
为什么呢?
原因在于,在处理 request 时,诸如记录请求、将应用程序错误转换为 HTTP 500 错误、验证用户等一些操作,这是每个处理程序都要执行的动作。
本文是 "构建属于自己的 Web 框架" 系列文章中的第二篇:
基础入门
首先,使用 net/http 包创建一个简单版本的 HTTP Server 应用。
代码如下:
http.HandleFunclocation patternhandlerhandlerhttp.HandleFunchttp.Handler接口定义如下:
示例代码如下:
http.HandlerServeHTTP(http.ResponseWriter, *http.Request)添加日志
现在,我们希望通过增加一个简单的日志,记录处理每个请求所花费的时间。
代码如下:
输出内容如下:
继续,我们增加第二个 handler。毕竟,只有一个路由的应用程序并不多。
代码重复! 该如何解决呢?
我们可以创建一个带有闭包的函数。但是,当我们有多个这样的函数时,它就会变得像 Javascript 中的回调一样糟糕,我们并不想如此。
链接处理
我们希望有一种类似 Rack、Ring、Connect.js 等的中间件系统的解决方案,链接多个处理程序。标准库中已经有这种实现的示例:
http.StripPrefix(prefix, handler)http.TimeoutHandler(handler, duration, message)handlerhandlerfunc (http.Handler) http.Handlerhandlerhandler实现代码如下:
但如此还是很麻烦,一遍又一遍地重复堆栈。 有没有什么更优雅的方式实现呢?
通用包 alice
handlerhandler问题解决!
我们已经有了一个使用标准接口的中间件系统,alice 有 50 行代码,一个非常小的依赖。如果想了解 alice 的实现细节,可自行阅读 alice 源码。
多个参数的 Handler
http.StripPrefix(prefix, handler)handlerfunc (http.Handler) http.Handler怎么办?
handlerfunc (http.Handler) http.Handler现在,新的 handler 我们在 alice 中间件系统可以开始使用了。
再谈 logging middleware
通过 alice,我们有了更加优雅的方式实现代码重复的删除。我们无需重新定义的一个新的 http.Handler 接口,标准接口即可满足要求,这意味学习成本非常低,依赖更少。
实现代码如下:
handler大功告成!
新中间件:panic recovery
panic recoverypanicdeferpanic现在,将它追加到我们的中间件 stack 中。
总结
func (http.Handler) http.Handlerhttp.Handler而通过链接方式实现中间件系统,已经是非常流行的方案,比如 Gorilla 和标准库本身。 我认为这是最惯用的方式。
两个中间件:logging 和 panice recovery。
handler接下来的一部分,我们将会了解到,在中间件之间共享值时,我们可能要更改一些内容。但它其实没有那么大的变化,我们没有理由重写已有的中间件。