golang轻量级net/http中间件插件库interpose的使用

Golang轻量级net/http中间件插件库interpose的使用

介绍

Interpose是一个用于Golang的简约net/http中间件框架。它使用http.Handler作为其核心功能单元,最大限度地减少了复杂性,并最大限度地提高了与其他中间件框架的互操作性。

它只做一件事:管理中间件。它没有任何内置功能,你需要自己提供路由器等组件。因为它基于net/http标准,Interpose可以与Gorilla框架、goji、nosurf以及许多其他框架和独立中间件开箱即用。

基本用法示例

以下是一个使用Interpose的示例,该中间件为每个响应添加HTTP头"X-Server-Name"。

创建一个main.go文件,内容如下:

package main

import (
	"fmt"
	"net/http"

	"github.com/carbocation/interpose"
)

func main() {
	middle := interpose.New()

	// 发送一个header告诉世界这个响应来自Interpose测试服务器
	// 你可以想象在其他情况下设置Content-type application/json或其他有用的headers
	middle.UseHandler(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
		rw.Header().Set("X-Server-Name", "Interpose Test Server")
	}))

	// 在这个例子中,我们使用一个基本路由器,它有一个匹配任何路径的catchall路由
	// 最后添加的中间件最后执行,所以通过最后添加路由器,我们的其他中间件有机会在路由器写入HTTP Body之前修改HTTP headers
	router := http.NewServeMux()
	middle.UseHandler(router)

	router.Handle("/", http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
		fmt.Fprintf(w, "Welcome to %s!", req.URL.Path)
	}))

	http.ListenAndServe(":3001", middle)
}

在同一目录下运行go run main.go,然后访问http://localhost:3001/world查看输出。

路由、优雅关闭和headers

在这个例子中,我们使用graceful包在遇到关闭信号后优雅地释放连接。使用比前一个例子更强大的路由器Gorilla mux。我们还向浏览器发送headers,指示这是来自名为"Interpose Test Server"的服务器。

package main

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

	"github.com/carbocation/interpose"
	"github.com/gorilla/mux"
	"github.com/stretchr/graceful"
)

func main() {
	middle := interpose.New()

	// 告诉浏览器这个响应来自哪个服务器
	// 这修改了headers,所以我们希望在可能修改body的任何中间件之前调用它
	middle.Use(func(next http.Handler) http.Handler {
		return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
			rw.Header().Set("X-Server-Name", "Interpose Test Server")
			next.ServeHTTP(rw, req)
		})
	})

	// 应用路由器。通过最后添加它,我们的其他中间件将在路由器之前执行,
	// 允许我们在任何输出生成之前修改headers
	router := mux.NewRouter()
	middle.UseHandler(router)

	router.HandleFunc("/{user}", func(w http.ResponseWriter, req *http.Request) {
		fmt.Fprintf(w, "Welcome to the home page, %s!", mux.Vars(req)["user"])
	})

	// 启动并允许优雅关闭,给现有连接最多10秒时间结束
	graceful.Run(":3001", 10*time.Second, middle)
}

组合日志和gzip压缩

打印Apache CombinedLog兼容的日志语句到StdOut,并在客户端具有gzip能力时gzip压缩HTTP响应:

package main

import (
	"compress/gzip"
	"fmt"
	"net/http"

	"github.com/carbocation/interpose"
	"github.com/carbocation/interpose/middleware"
	"github.com/gorilla/mux"
)

func main() {
	middle := interpose.New()

	// 首先应用不会写入HTTP body输出的中间件

	// 使用Gorilla框架的组合日志
	middle.Use(middleware.GorillaLog())

	// 使用Negroni的Gzip功能
	middle.Use(middleware.NegroniGzip(gzip.DefaultCompression))

	// 现在应用可以修改HTTP body的中间件
	router := mux.NewRouter()
	middle.UseHandler(router)

	router.HandleFunc("/{user}", func(w http.ResponseWriter, req *http.Request) {
		fmt.Fprintf(w, "Welcome to the home page, %s!", mux.Vars(req)["user"])
	})

	http.ListenAndServe(":3001", middle)
}

嵌套中间件:只为某些路由添加headers

在最后一个例子中,我们为不同的路由应用了不同的中间件。在这里,我们将扩展这个想法,在不同的路由中创建完全嵌套的中间件堆栈。这种方法虽然比上一个例子更详细,但功能强大。在这个例子中,以/green开头的路由被赋予一个特殊的HTTP头X-Favorite-Color: green,但你可以想象使用相同的方法自动为JSON请求应用JSON内容头,在受保护的路径前添加认证等。

package main

import (
	"compress/gzip"
	"fmt"
	"net/http"

	"github.com/carbocation/interpose"
	"github.com/carbocation/interpose/middleware"
	"github.com/gorilla/mux"
)

func main() {
	middle := interpose.New()

	// 首先调用可能操作HTTP headers的中间件,因为它们必须在HTTP body被操作之前调用

	// 使用Gorilla框架的组合日志
	middle.Use(middleware.GorillaLog())

	// 使用Negroni的Gzip功能
	middle.Use(middleware.NegroniGzip(gzip.DefaultCompression))

	// 现在调用可以操作HTTP body的中间件

	// 定义路由器。注意,如果我们愿意,可以在定义路由之前将路由器添加到我们的中间件堆栈中
	router := mux.NewRouter()
	middle.UseHandler(router)

	// 配置我们的路由器
	router.HandleFunc("/{user}", func(w http.ResponseWriter, req *http.Request) {
		fmt.Fprintf(w, "Welcome to the home page, %s!", mux.Vars(req)["user"])
	})

	// 定义仅适用于某些路由的中间件
	greenMiddle := interpose.New()

	// 告诉主路由器将/green请求发送到我们的子路由器
	// 同样,我们可以在定义完整的中间件堆栈之前完成此操作
	router.Methods("GET").PathPrefix("/green").Handler(greenMiddle)

	// 在二级中间件中,就像上面一样,我们希望调用任何会修改HTTP headers的东西,然后才修改body
	greenMiddle.UseHandler(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
		rw.Header().Set("X-Favorite-Color", "green")
	}))

	// 最后,基于我们对绿色的热爱定义一个子路由器
	// 当你调用任何URL如http://localhost:3001/green/man时,
	// 你还会看到一个名为X-Favorite-Color的HTTP头,值为"green"
	greenRouter := mux.NewRouter().Methods("GET").PathPrefix("/green").Subrouter()
	greenMiddle.UseHandler(greenRouter)

	greenRouter.HandleFunc("/{user}", func(w http.ResponseWriter, req *http.Request) {
		fmt.Fprintf(w, "Welcome to the home page, green %s!", mux.Vars(req)["user"])
	})

	http.ListenAndServe(":3001", middle)
}

适配器

一些不完全兼容http.Handler的框架使用的中间件可以很容易地转换为Interpose兼容的中间件。目前已经为Martini和Negoni创建了适配器。

例如,要在Interpose中使用github.com/urfave/negroni中间件,你可以使用adaptors.FromNegroni:

middle := interpose.New()

// 有签名`negroni.Handler`
negroniMiddleware := negronilogrus.NewMiddleware()

// 在Interpose中使用Negroni中间件
middle.Use(adaptors.FromNegroni(negroniMiddleware))

更多示例可以在examples文件夹及其子文件夹menagerie中找到。


更多关于golang轻量级net/http中间件插件库interpose的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang轻量级net/http中间件插件库interpose的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


Golang轻量级中间件库Interpose使用指南

Interpose是一个轻量级的Golang HTTP中间件库,它提供了简单的方式来组织和链式调用中间件。下面我将详细介绍Interpose的使用方法。

基本安装

首先安装interpose库:

go get github.com/carbocation/interpose

基础使用示例

package main

import (
	"fmt"
	"net/http"
	
	"github.com/carbocation/interpose"
)

func main() {
	middle := interpose.New()
	
	// 添加简单的中间件
	middle.Use(func(next http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			fmt.Println("Before handler")
			next.ServeHTTP(w, r)
			fmt.Println("After handler")
		})
	})
	
	// 设置最终处理程序
	middle.UseHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("Hello, Interpose!"))
	}))
	
	http.ListenAndServe(":8080", middle)
}

常用功能

1. 多个中间件链式调用

func main() {
	middle := interpose.New()
	
	// 中间件1 - 日志记录
	middle.Use(func(next http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			log.Printf("Request: %s %s", r.Method, r.URL.Path)
			next.ServeHTTP(w, r)
		})
	})
	
	// 中间件2 - 认证检查
	middle.Use(func(next http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			if r.Header.Get("X-Auth-Token") != "secret" {
				http.Error(w, "Unauthorized", http.StatusUnauthorized)
				return
			}
			next.ServeHTTP(w, r)
		})
	})
	
	// 最终处理程序
	middle.UseHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("Authenticated content"))
	}))
	
	http.ListenAndServe(":8080", middle)
}

2. 路由分组

Interpose支持路由分组,可以为不同的路由路径应用不同的中间件:

func main() {
	middle := interpose.New()
	
	// 全局中间件
	middle.Use(func(next http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			w.Header().Set("X-Frame-Options", "DENY")
			next.ServeHTTP(w, r)
		})
	})
	
	// API路由组
	apiRouter := interpose.New()
	apiRouter.Use(func(next http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			w.Header().Set("Content-Type", "application/json")
			next.ServeHTTP(w, r)
		})
	})
	apiRouter.UseHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte(`{"status":"ok"}`))
	}))
	
	// 将路由组挂载到特定路径
	middle.UseHandler(http.StripPrefix("/api", apiRouter))
	
	// 默认路由
	middle.UseHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("Welcome to homepage"))
	}))
	
	http.ListenAndServe(":8080", middle)
}

3. 从第三方库导入中间件

Interpose兼容标准的http.Handler接口,可以轻松集成其他中间件:

import (
	"github.com/gorilla/handlers"
)

func main() {
	middle := interpose.New()
	
	// 使用gorilla/handlers的日志中间件
	middle.UseHandler(handlers.LoggingHandler(os.Stdout, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("Hello with logging"))
	})))
	
	http.ListenAndServe(":8080", middle)
}

高级用法

1. 上下文传递

func main() {
	middle := interpose.New()
	
	// 中间件设置值
	middle.Use(func(next http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			// 创建一个新的context
			ctx := context.WithValue(r.Context(), "user", "admin")
			next.ServeHTTP(w, r.WithContext(ctx))
		})
	})
	
	// 处理程序读取值
	middle.UseHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		user := r.Context().Value("user").(string)
		w.Write([]byte("Hello, " + user))
	}))
	
	http.ListenAndServe(":8080", middle)
}

2. 错误处理中间件

func main() {
	middle := interpose.New()
	
	// 错误处理中间件
	middle.Use(func(next http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			defer func() {
				if err := recover(); err != nil {
					http.Error(w, "Internal Server Error", http.StatusInternalServerError)
					log.Printf("Panic: %v", err)
				}
			}()
			next.ServeHTTP(w, r)
		})
	})
	
	// 可能panic的处理程序
	middle.UseHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		panic("something went wrong")
	}))
	
	http.ListenAndServe(":8080", middle)
}

总结

Interpose是一个简单而强大的中间件库,主要特点包括:

  1. 轻量级,API简洁
  2. 兼容标准http.Handler接口
  3. 支持中间件链式调用
  4. 支持路由分组
  5. 易于集成其他中间件

虽然Interpose不如一些更全面的框架(如Gin或Echo)功能丰富,但对于需要轻量级中间件解决方案的项目来说,它是一个很好的选择。

回到顶部