面试题答案
一键面试设计思路
- 定义匿名函数:在Go语言中,匿名函数是没有函数名的函数。在Web框架的中间件设计中,匿名函数可作为中间件的载体。每个中间件匿名函数接收一个
http.Handler
类型的参数(代表下一个处理程序),并返回一个新的http.Handler
。 - 闭包特性:利用闭包,中间件函数可以访问和修改其外部函数作用域中的变量。例如,在中间件中可以设置一些全局的上下文信息,这些信息可以被后续的中间件或最终的处理程序访问。
- 数据传递:通过在请求的上下文(
context.Context
)中传递数据来实现中间件之间的数据共享。context.Context
是Go语言中用于在不同的函数调用之间传递请求特定数据、取消信号和截止时间的标准方式。 - 顺序执行:中间件按照定义的顺序依次执行。最外层的中间件首先执行,然后将处理权交给内层的中间件,直到到达最终的处理程序。处理程序处理完请求后,再反向经过中间件进行后续处理(如日志记录等)。
关键代码示例
package main
import (
"context"
"fmt"
"net/http"
)
// 定义一个中间件函数类型
type Middleware func(http.Handler) http.Handler
// 日志中间件
func Logger(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Println("Logging: Request received")
next.ServeHTTP(w, r)
fmt.Println("Logging: Request processed")
})
}
// 认证中间件
func Authentication(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// 假设这里进行认证逻辑
ctx := context.WithValue(r.Context(), "user", "authenticatedUser")
r = r.WithContext(ctx)
next.ServeHTTP(w, r)
})
}
// 组合中间件
func ChainMiddleware(middlewares []Middleware, next http.Handler) http.Handler {
for i := len(middlewares) - 1; i >= 0; i-- {
next = middlewares[i](next)
}
return next
}
// 最终的处理程序
func Handler(w http.ResponseWriter, r *http.Request) {
user := r.Context().Value("user")
fmt.Fprintf(w, "Hello, %v", user)
}
func main() {
middlewares := []Middleware{Logger, Authentication}
http.Handle("/", ChainMiddleware(middlewares, http.HandlerFunc(Handler)))
http.ListenAndServe(":8080", nil)
}
在上述代码中:
Logger
和Authentication
是两个中间件,它们都是匿名函数(通过http.HandlerFunc
转换),利用闭包访问外部变量并处理请求。ChainMiddleware
函数将多个中间件按顺序组合在一起,从后往前依次包装http.Handler
。- 最终的
Handler
函数从请求的上下文中获取认证中间件设置的用户信息,并返回响应。