Golang middleware 链式调用

 

    基于web的Golang middleware 链式调用,原文地址在如下  gowebexamples

https://gowebexamples.com/advanced-middleware/

对其调用过程简化及分析如下;

package main

import (
    "fmt"
    "time"
)

type HandlerFunc func()

type Middleware func(HandlerFunc) HandlerFunc

func Timing(x int) Middleware {

    return func(f HandlerFunc) HandlerFunc {
        return func() {
            start := time.Now()

            defer func() {
                fmt.Println("elapse ", time.Since(start))
            }()

            fmt.Println("in timing", x)

            f()
        }
    }
}

func Method(s string) Middleware {

    return func(f HandlerFunc) HandlerFunc {
        return func() {
            fmt.Println("in method ", s)

            f()
        }
    }
}

func Chain(f HandlerFunc, middlerwares ...Middleware) HandlerFunc {
    for _, m := range middlerwares {
        f = m(f)
    }

    return f
}

func Hello() {
    fmt.Println("in Hello")
}

func iterate(f HandlerFunc) {
    f()
}

func main() {

    iterate(Chain(Hello, Timing(5), Method("get")))
}

 

        调用过程为,在Chain 函数中,Hello 函数作为第一个参数, 调用Timing(5) 后的返回值,匿名函数

func(f HandlerFunc) HandlerFunc,作为第二参数, 调用Method("get")后的返回值,匿名函数作为第三个参数。
  遍历每个middleware ,调用第一个Timing(5)的返回值,匿名函数时,将Hello 函数作为参数,此时,匿名函数的返回值中的
f() 即为Hello 函数。返回值为一个包含了Timing 和Hello 函数的
return func() 函数,
将此时的返回值作为参数赋值给调用的Method 函数, 类似于函数入栈
遍历结束后,返回此时的函数,即Method 中的包含打印信息和 f() 的函数。
在iterate 中调用上面的最后一个返回函数,类似于函数出栈,就会依次打印:

in method get
in timing 5
in Hello
elapse 0s

 

附 :  gowebexamples.com 中的Advanced Middleware 如下:

 

// advanced-middleware.go
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)
}

 

posted on 2023-05-10 17:40  wallywl  阅读(149)  评论(0)    收藏  举报