写点什么

Go Web 编程入门:中间件

作者:宇宙之一粟
  • 2022 年 5 月 25 日
  • 本文字数:2313 字

    阅读完需:约 8 分钟

Go Web 编程入门:中间件

前言

中间件通常位于前端的客户端站点请求和请求的后端资源之间。中间件非常有用,尤其是当我们希望在进行 API 调用之前进行一些验证,例如请求方法、标头和 JWT 等。


日志中间件


http.Handler 包装器是一个具有一个输入参数和一个输出参数的函数,两者都是 http.Handler 类型。

func Middleware(next http.Handler) http.Handler {	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {        //code before make the backend api call
next.ServeHTTP(w, r) //serve and handle the http request
//code after make the backend api call })}
复制代码

现在,而不是直接服务和监听我们的 http 处理程序,例如:

http.ListenAndServe(":3000", handler)
复制代码

我们现在可以将它包装在我们的中间件中并变成:

http.ListenAndServe(":3000", Middleware(handler))
复制代码


接下来将介绍如何创建一个 Go 语言的日志中间件。


中间件只需将 http.HandlerFunc 作为其参数之一,将其包装并返回一个新的 http.HandlerFunc 供服务器调用。


新建一个 main.go 文件:

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)}
复制代码


创建 mod 文件:

$ go mod init main.go go: creating new go.mod: module main.gogo: to add module requirements and sums:        go mod tidy
复制代码


打开另一个终端:

$ curl -s http://localhost:8080/foofoo$ curl -s http://localhost:8080/barbar$ curl -s http://localhost:8080/foo\?barfoo
复制代码

运行上述代码:

$ go run main.go         2022/05/25 23:12:00 /foo2022/05/25 23:12:09 /bar2022/05/25 23:12:16 /foo
复制代码


中间件框架

中间件本身只是将 a 作为其参数之一,将其包装并返回一个新的供服务器调用。在这里,我们定义了一种新类型,它最终使将多个中间件链接在一起变得更加容易。这个想法的灵感来自于 Mat Ryers 关于构建 API 的演讲。

这个片段详细解释了如何创建一个新的中间件。在下面的完整示例中,代码结构示例如下:

func createNewMiddleware() Middleware {
// Create a new Middleware middleware := func(next http.HandlerFunc) http.HandlerFunc {
// Define the http.HandlerFunc which is called by the server eventually handler := func(w http.ResponseWriter, r *http.Request) {
// ... do middleware things
// Call the next middleware/handler in chain next(w, r) }
// Return newly created handler return handler }
// Return newly created middleware return middleware}
复制代码

完整测试

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 processfunc 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 Requestfunc 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.HandlerFuncfunc 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)}
复制代码

运行代码:

$ go run main.go 
复制代码

打开另外的终端:

$ curl -s http://localhost:8080/hello world
$ curl -s -XPOST http://localhost:8080/Bad Request
复制代码


$ go run main.go         2022/05/25 23:20:01 / 21.595µs2022/05/25 23:20:13 / 5.129µs
复制代码


参考链接:

发布于: 2022 年 05 月 25 日阅读数: 18
用户头像

宇宙古今无有穷期,一生不过须臾,当思奋争 2020.05.07 加入

🏆InfoQ写作平台-第二季签约作者 🏆 混迹于江湖,江湖却没有我的影子 热爱技术,专注于后端全栈,轻易不换岗 拒绝内卷,工作于软件工程师,弹性不加班 热衷分享,执着于阅读写作,佛系不水文

评论

发布
暂无评论
Go Web 编程入门:中间件_中间件_宇宙之一粟_InfoQ写作社区