这一期我们简单讲讲如何创建并使用中间件(Middleware)。首先讲一讲如何创建中间件,先看下面的 ListenAndServe
函数:
func ListenAndServe(addr string, handler Handler) error
该函数的第一个参数为监听的地址,第二个参数是 handler ,如果是 nil 的话,就是 DefaultServeMux 。如果是自定义 handler 的话,该 handler 必须实现 ServeHTTP
方法, handler 接口定义如下:
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}
接下来就开始创建中间件,先创建一个 struct ,该 struct 有一个字段,该字段实现 http.Handler
接口:
type MyMiddleware struct {
Next http.Handler
}
此外,如果想要 MyMiddleware 也是一个 handler ,它就需要实现 ServeHTTP
方法:
func(m MyMiddleware) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// 在 next handler 之前做一些事情
m.Next.ServeHTTP(w, r)
// 在 next handler 之后做一些事情
}
下面直接讲一个简单的例子,该例子目的是创建一个中间件,验证 HTTP 请求中的 Authorization
字段,如果该字段为空,则返回 401 ,否则返回数据,实现一个类似认证的功能。首先创建一个名为 middleware
的 package ,并在此目录下创建 auth.go 文件,用于编写中间件:
package middleware
import "net/http"
// 中间件
type AuthMiddleware struct {
Next http.Handler
}
// 实现 ServeHTTP 方法
func (am *AuthMiddleware) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// 如果中间件 Next 字段为 nil
if am.Next == nil {
// 就将其设置为默认的 DefaultServeMux
am.Next = http.DefaultServeMux
}
// 读取 HTTP 的 Authorization 字段信息
auth := r.Header.Get("Authorization")
// 当验证字段不为空的情况下返回数据
// 否则返回 401 未认证
if auth != "" {
am.Next.ServeHTTP(w, r)
} else {
w.WriteHeader(http.StatusUnauthorized)
}
}
接着我们创建 main.go 文件,这里创建了一个结构体,并使用 JSON 发送数据:
package main
import (
"encoding/json"
"goweb/middleware"
"net/http"
)
type Person struct {
Name string
Age int64
}
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
p := Person{
Name: "Caizi",
Age: 18,
}
enc := json.NewEncoder(w)
enc.Encode(p)
})
http.ListenAndServe("localhost:8080", new(middleware.AuthMiddleware))
}
接着编写测试文件 test.http ,首先我们测试当 Authorization
字段为空的情况:
GET http://localhost:8080/ HTTP/1.1
运行程序,并进行测试,得到以下的响应:
GET http://localhost:8080
HTTP/1.1 401 Unauthorized
Date: Wed, 16 Feb 2022 08:48:10 GMT
Content-Length: 0
<Response body is empty>
Response code: 401 (Unauthorized); Time: 23ms; Content length: 0 bytes
接着测试当 Authorization
字段不为空的情况:
GET http://localhost:8080/ HTTP/1.1
Authorization: a
进行测试后,得到的响应如下:
GET http://localhost:8080
HTTP/1.1 200 OK
Date: Wed, 16 Feb 2022 08:51:20 GMT
Content-Length: 26
Content-Type: text/plain; charset=utf-8
{"Name":"Caizi","Age":18}
Response code: 200 (OK); Time: 61ms; Content length: 26 bytes
中间件有许多用途,例如日志、处理请求超时等情况。