7.9 GO中间件(Middleware )
中间件是一种计算机软件,可为操作系统提供的软件应用程序提供服务,以便于各个软件之间的沟通,特别是系统软件和应用软件。广泛用于web应用和面向服务的体系结构等。
纵观GO语言,中间件应用比较普遍,主要应用:
- 记录对服务器发送的请求(request)
- 处理服务器响应(response )
- 请求和处理之间做一个权限认证工作
- 远程调用
- 安全
- 等等
中间件处理程序是简单的http.Handler
,它包装另一个http.Handler
做请求的一些预处理和/或后处理。它被称为“中间件”,因为它位于Go Web服务器和实际处理程序之间的中间位置。
下面是一些中间件例子
记录日志中间件
package main
import (
"fmt"
"log"
"net/http"
)
func logging(f http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
log.Println(r.URL.Path)
f(w, r)
}
}
func foo(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "foo")
}
func bar(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "bar")
}
func main() {
http.HandleFunc("/foo", logging(foo))
http.HandleFunc("/bar", logging(bar))
http.ListenAndServe(":8080", nil)
}
返回结果
foo
将上面示例修改下,也可以实现相同的功能。
package main
import (
"fmt"
"log"
"net/http"
)
func foo(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "foo")
}
func bar(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "bar")
}
func loggingMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
log.Println(r.URL.Path)
next.ServeHTTP(w, r)
})
}
func main() {
http.Handle("/foo", loggingMiddleware(http.HandlerFunc(foo)))
http.Handle("/bar", loggingMiddleware(http.HandlerFunc(bar)))
http.ListenAndServe(":8080", nil)
}
返回结果
foo
多中间件例子
package main
import (
"fmt"
"log"
"net/http"
"time"
)
type Middleware func(http.HandlerFunc) http.HandlerFunc
// Logging logs all requests with its path and the time it took to process
func Logging() Middleware {
// Create a new Middleware
return func(f http.HandlerFunc) http.HandlerFunc {
// Define the http.HandlerFunc
return func(w http.ResponseWriter, r *http.Request) {
// Do middleware things
start := time.Now()
defer func() { log.Println(r.URL.Path, time.Since(start)) }()
// Call the next middleware/handler in chain
f(w, r)
}
}
}
// Method ensures that url can only be requested with a specific method, else returns a 400 Bad Request
func Method(m string) Middleware {
// Create a new Middleware
return func(f http.HandlerFunc) http.HandlerFunc {
// Define the http.HandlerFunc
return func(w http.ResponseWriter, r *http.Request) {
// Do middleware things
if r.Method != m {
http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
return
}
// Call the next middleware/handler in chain
f(w, r)
}
}
}
// Chain applies middlewares to a http.HandlerFunc
func Chain(f http.HandlerFunc, middlewares ...Middleware) http.HandlerFunc {
for _, m := range middlewares {
f = m(f)
}
return f
}
func Hello(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "hello world")
}
func main() {
http.HandleFunc("/", Chain(Hello, Method("GET"), Logging()))
http.ListenAndServe(":8080", nil)
}
中间件本身只是将其http.HandlerFunc
作为其参数之一,包装它并返回一个新http.HandlerFunc
的服务器来调用。在这里,我们定义了一种新类型Middleware
,最终可以更容易地将多个中间件链接在一起。
当然我们也可以改成如下形式
package main
import (
"fmt"
"log"
"net/http"
"time"
)
type Middleware func(http.Handler) http.Handler
func Hello(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "hello world")
}
func Chain(f http.Handler, mmap ...Middleware) http.Handler {
for _, m := range mmap {
f = m(f)
}
return f
}
func Method(m string) Middleware {
return func(f http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
log.Println(r.URL.Path)
if r.Method != m {
http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
return
}
f.ServeHTTP(w, r)
})
}
}
func Logging() Middleware {
return func(f http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
//log.Println(r.URL.Path)
// Do middleware things
start := time.Now()
defer func() { log.Println(r.URL.Path, time.Since(start)) }()
f.ServeHTTP(w, r)
})
}
}
func main() {
http.Handle("/", Chain(http.HandlerFunc(Hello), Method("GET"), Logging()))
http.ListenAndServe(":8080", nil)
}
在gin框架下实现中间件
r := gin.Default() 创建带有默认中间件的路由,默认是包含logger和recovery中间件的
r :=gin.new() 创建带有没有中间件的路由
示例
package main
import (
"github.com/gin-gonic/gin"
"log"
"time"
)
func Logger() gin.HandlerFunc {
return func(c *gin.Context) {
t := time.Now()
// Set example variable
c.Set("example", "12345")
// before request
c.Next()
// after request
latency := time.Since(t)
log.Print(latency) //时间 0s
// access the status we are sending
status := c.Writer.Status()
log.Println(status) //状态 200
}
}
func main() {
r := gin.New()
r.Use(Logger())
r.GET("/test", func(c *gin.Context) {
example := c.MustGet("example").(string)
// it would print: "12345"
log.Println(example)
})
// Listen and serve on 0.0.0.0:8080
r.Run(":8080")
}
以上示例也可改为
package main
import (
"github.com/gin-gonic/gin"
"log"
"time"
)
func Logger(c *gin.Context) {
t := time.Now()
// Set example variable
c.Set("example", "12345")
// before request
c.Next()
// after request
latency := time.Since(t)
log.Print(latency) //时间 0s
// access the status we are sending
status := c.Writer.Status()
log.Println(status) //状态 200
}
func main() {
r := gin.New()
r.Use(Logger)
r.GET("/test", func(c *gin.Context) {
example := c.MustGet("example").(string)
// it would print: "12345"
log.Println(example)
})
// Listen and serve on 0.0.0.0:8080
r.Run(":8080")
}
以上示例也可改为
package main
import (
"github.com/gin-gonic/gin"
"log"
"time"
)
func Logger() gin.HandlerFunc {
return func(c *gin.Context) {
t := time.Now()
// Set example variable
c.Set("example", "12345")
// before request
c.Next()
// after request
latency := time.Since(t)
log.Print(latency) //时间 0s
// access the status we are sending
status := c.Writer.Status()
log.Println(status) //状态 200
}
}
func main() {
r := gin.New()
r.GET("/test", Logger(), func(c *gin.Context) {
example := c.MustGet("example").(string)
// it would print: "12345"
log.Println(example)
})
// Listen and serve on 0.0.0.0:8080
r.Run(":8080")
}
即不用r.use添加中间件,直接将Logger() 写到r.GET 方法的参数里(”/test”之后)。
更多gin中间件示例可参考 https://github.com/gin-gonic/gin
参考资料
https://drstearns.github.io/tutorials/gomiddleware/
https://gowebexamples.com/advanced-middleware/
links
- 目录
- 上一节:处理文件
- 下一节:Redirect 重定向