GolangWeb编程之控制器方法HandlerFunc与中间件Middleware

原文链接:

原创 晓兵XB 云原生云 今天

收录于话题

#golang 6

#web 1

#中间件 1

背景

Golang Web编程中需要区分并解耦业务和非业务代码, 对于在请求和响应之间的非业务代码, 适合用中间件进行串联来处理.

哪些场景适合串联中间件?

  • 对http响应进行压缩处理
  • 日志打印请求路径, 请求时间等
  • 挂载golang性能分析工具pprof需要的路由, 如/pprof, /pprof/trace到系统中
  • 从请求头中读取X-Forwarded-For和X-Real-IP, 将http.Request中的远端IP地址RemoteAddr修改为得到的真实IP地址RealIP
  • 为本次请求生成单独的requestid, 可以透传跟踪, 生成分布式调用链路,也可用于在日志中串联单次请求的所有逻辑
  • 用context.Timeout设置超时时间, 将其通过http.Request一路透传下去
  • 通过固定长度的channel存储token, 并通过这些token对接口进行限流, 接口token验证等

中间件核心原理

Go的http包中拥有一种HandlerFunc函数类型(控制器函数), 可以把一个带有正确签名的函数f,转换成一个带有方法f的Handler,类似闭包,达到函数串联的效果, 参考流程图如下:



示例代码如下:

流程分析:

  • main函数开始执行, 通过Chain方法将控制器函数Hello, 中间件Method, 中间件Logging串联起来, 解耦业务逻辑Hello和其他功能, Chain方法签名要求传入一个http控制器方法,如Hello, 和多个中间件Middleware, 最后返回串联后的控制器方法f
http.HandleFunc("/", Chain(Hello, Method("GET"), Logging()))
  • 中间件Middleware是一个函数签名, 参数为http控制器方法, 返回也是http控制器方法
type Middleware func(http.HandlerFunc) http.HandlerFunc
  • 中间件Logging与Method类似, 这里以Logging为例进行讲解, 方法Logging签名要求返回一个中间件Middleware, 所以内部采用匿名函数构造一个与Middleware签名一致的方法进行返回, 该http控制器方法内部又返回一个控制器函数(签名与Hello一样)
func(w http.ResponseWriter, r *http.Request) {

在该控制器函数内部完成请求路径打印以及耗时统计, 并引用外层函数f(w, r), 形成闭包, 串联调用,很多地方也写成next(w, r), 闭包内部使用的引用类型, 如这里的f, 构成一个整体

  • http.HandleFunc是另一个控制器方法(注意与http.HandlerFunc区分), 要求传入一个路径和http控制器方法HandlerFunc, http库在处理请求的时候先获取控制器方法, 然后调用控制器方法的ServeHTTP方法, 最后调用控制器函数Hello(w, r)
  • 这里需要注意的是, 普通控制器函数Hello并没有实现ServeHTTP方法, 是通过控制器方法将普通handler方法转为http.HandlerFunc(), 如http.HandlerFunc(Hello), 控制器函数HandlerFunc实现了接口Handler interface, 只要普通控制器函数(Hello)和http.HandlerFunc()有一致的函数签名,就可以将该handler()函数进行类型转换,转为http.HandlerFunc, 在http库需要调用你的handler函数来处理http请求时,会调用HandlerFunc()的ServeHTTP()

参考文档:

Go Web编程

Go语言高级编程

END已结束



欢迎大家留言, 订阅, 交流哦!