中间件(基础和进阶)

基础中间件

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")
}

logging方法中,请求执行方法嵌套了请求执行方法。外层的请求执行方法用于打印日志,里面的请求执行方法用于处理http请求。
foo方法和bar方法分别是具体的请求执行方法。

http.HandleFunc("/foo", logging(foo))
http.HandleFunc("/bar", logging(bar))
http.ListenAndServe(":8090", nil)

以上代码,将请求执行方法和url路径关联,并监听指定端口号。

以下是完整代码:

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(":8090", nil)
}

进阶中间件

type Middleware func(http.HandlerFunc) http.HandlerFunc

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

Middleware是中间件的类型,该类型是一个方法,参数是请求响应方法,返回的也是请求响应方法。
Chain方法的功能是包装请求响应方法,也就是在参数f这个请求响应方法的外层逐层包装中间件。

func Logging() Middleware {
	return func(f http.HandlerFunc) http.HandlerFunc {
		return func(w http.ResponseWriter, r *http.Request) {
			start := time.Now()
			defer func() { log.Println(r.URL.Path, time.Since(start)) }()
			f(w, r)
		}
	}
}

func Method(m string) Middleware {
	return func(f http.HandlerFunc) http.HandlerFunc {
		return func(w http.ResponseWriter, r *http.Request) {
			if r.Method != m {
				http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
				return
			}
			f(w, r)
		}
	}
}

以上代码会包装请求响应方法,扩展其功能。

以下是完整代码:

package main

import (
	"fmt"
	"log"
	"net/http"
	"time"
)

type Middleware func(http.HandlerFunc) http.HandlerFunc

func Logging() Middleware {
	return func(f http.HandlerFunc) http.HandlerFunc {
		return func(w http.ResponseWriter, r *http.Request) {
			start := time.Now()
			defer func() { log.Println(r.URL.Path, time.Since(start)) }()
			f(w, r)
		}
	}
}

func Method(m string) Middleware {
	return func(f http.HandlerFunc) http.HandlerFunc {
		return func(w http.ResponseWriter, r *http.Request) {
			if r.Method != m {
				http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
				return
			}
			f(w, r)
		}
	}
}

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(":8090", nil)
}

以上代码有个问题,当中间件过多时,http.HandlerFunc会嵌套很多层。

完善中间件

type Middleware func(http.ResponseWriter, *http.Request) bool

func Chain(f http.HandlerFunc, middlewares ...Middleware) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		for _, m := range middlewares {
			if !m(w, r) {
				return
			}
		}
		f(w, r)
	}
}

相比上面的代码,Middleware类型的返回值不再是http.HandlerFunc,而是bool。

func Logging() Middleware {
	return func(w http.ResponseWriter, r *http.Request) bool {
		start := time.Now()
		defer func() { log.Println(r.URL.Path, time.Since(start)) }()
		return true
	}
}

func Method(m string) Middleware {
	return func(w http.ResponseWriter, r *http.Request) bool {
		if r.Method != m {
			http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
			return false
		}
		return true
	}
}

中间件的功能也做了改动。相比之前的代码,现在中间件更专注于自身应有的功能,并在满足条件时返回true,表示可执行下一步;否则,需要中断执行。

以下是完整代码:

package main

import (
	"fmt"
	"log"
	"net/http"
	"time"
)

type Middleware func(http.ResponseWriter, *http.Request) bool

func Logging() Middleware {
	return func(w http.ResponseWriter, r *http.Request) bool {
		start := time.Now()
		defer func() { log.Println(r.URL.Path, time.Since(start)) }()
		return true
	}
}

func Method(m string) Middleware {
	return func(w http.ResponseWriter, r *http.Request) bool {
		if r.Method != m {
			http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
			return false
		}
		return true
	}
}

func Chain(f http.HandlerFunc, middlewares ...Middleware) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		for _, m := range middlewares {
			if !m(w, r) {
				return
			}
		}
		f(w, r)
	}
}

func Hello(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintln(w, "hello world")
}

func main() {
	http.HandleFunc("/", Chain(Hello, Method("GET"), Logging()))
	http.ListenAndServe(":8090", nil)
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值