Go Web 编程入门:中间件
【摘要】 前言中间件通常位于前端的客户端站点请求和请求的后端资源之间。中间件非常有用,尤其是当我们希望在进行 API 调用之前进行一些验证,例如请求方法、标头和 JWT 等。日志中间件http.Handler 包装器是一个具有一个输入参数和一个输出参数的函数,两者都是 http.Handler 类型。func Middleware(next http.Handler) http.Handler { r...
前言
中间件通常位于前端的客户端站点请求和请求的后端资源之间。中间件非常有用,尤其是当我们希望在进行 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.go
go: to add module requirements and sums:
go mod tidy
打开另一个终端:
$ curl -s http://localhost:8080/foo
foo
$ curl -s http://localhost:8080/bar
bar
$ curl -s http://localhost:8080/foo\?bar
foo
运行上述代码:
$ go run main.go
2022/05/25 23:12:00 /foo
2022/05/25 23:12:09 /bar
2022/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 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)
}
运行代码:
$ 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µs
2022/05/25 23:20:13 / 5.129µs
参考链接:
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)