在构建 Go API 时,日志记录和错误处理是至关重要的组成部分,它们可以帮助你调试代码、监控 API 行为并为用户提供友好的错误提示。中间件提供了一种优雅的方式来实现这些功能,它允许你在请求到达你的 API 端点之前拦截请求并执行一些操作。
本文将引导你逐步添加日志记录和错误处理中间件到你的 Go API 中,使你的 API 更加健壮、易于维护和用户友好。
中间件就像你最喜欢的夜总会里的保安,它会在请求到达你的 API 端点之前拦截请求。你可以使用中间件来检查身份验证(比如我们在 JWT 中所做的那样)、记录信息或在出现错误时进行处理。
今天,我们将构建一个中间件,它可以:
记录:每个传入请求,以便我们知道谁在敲打我们的 API 的门。
处理错误:优雅地处理错误,这样你的用户就不会看到那些难看的 500 错误。
让我们深入研究吧!
日志记录是你调试和了解 API 中发生的事情时最好的朋友。我们将创建一个中间件,它记录每个传入请求——方法、URL 和所用时间。
import ( "log" "net/http" "time" ) func loggingMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { start := time.Now() // 记录方法和请求的 URL log.Printf("Started %s %s", r.Method, r.URL.Path) // 调用链中的下一个处理程序 next.ServeHTTP(w, r) // 记录所用时间 log.Printf("Completed in %v", time.Since(start)) }) }
这段代码定义了一个名为 loggingMiddleware 的函数,它接受一个 http.Handler 作为参数,并返回一个新的 http.Handler。这个新处理程序包含一个匿名函数,它会在每个请求到达时执行。在函数中,我们首先记录了请求的开始时间,然后记录了请求的方法和 URL。接下来,我们调用 next.ServeHTTP 将请求传递给链中的下一个处理程序。最后,我们记录了请求的处理时间。
让我们谈谈错误。错误会发生,对吧?但是,与其让它们导致崩溃或发送模糊的错误消息,不如让我们优雅地处理它们。
func errorHandlingMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { defer func() { if err := recover(); err != nil { // 记录错误并发送用户友好的消息 log.Printf("Error occurred: %v", err) http.Error(w, "Internal Server Error", http.StatusInternalServerError) } }() next.ServeHTTP(w, r) }) }
这段代码定义了一个名为 errorHandlingMiddleware 的函数,它接受一个 http.Handler 作为参数,并返回一个新的 http.Handler。这个新处理程序包含一个匿名函数,它会在每个请求到达时执行。在函数中,我们使用 defer 关键字来确保在函数返回之前执行一个匿名函数。这个匿名函数使用 recover() 函数来捕获任何恐慌,并记录错误信息,然后向客户端发送一个 500 错误。
现在我们已经构建了日志记录和错误处理中间件,让我们将它们连接到我们的 API。我们将全局应用它们,这样每个请求都会被记录,并且错误会被捕获。
import ( "fmt" "log" "net/http" "github.com/gorilla/mux" ) // ... 其他代码 ... func main() { // ... 其他代码 ... r := mux.NewRouter() // 全局应用中间件 r.Use(loggingMiddleware) r.Use(errorHandlingMiddleware) // ... 其他代码 ... fmt.Println("Server started on port :8000") log.Fatal(http.ListenAndServe(":8000", r)) }
在 main 函数中,我们首先创建了一个 mux.NewRouter 对象,它用于路由请求。然后,我们使用 r.Use 函数全局应用了 loggingMiddleware 和 errorHandlingMiddleware。这样,所有请求都会经过这两个中间件。
为了确保一切正常,启动你的 API:
go run main.go
现在,尝试访问你的任何端点(例如 /books)并检查你的终端。你应该看到类似以下的日志:
Started GET /books Completed in 1.2ms
如果出现错误,你会看到:
Error occurred: some error details
但是,你的用户只会看到一条干净的“500 内部服务器错误”消息。🎉
日志记录有助于你跟踪错误和监控 API 的行为。如果出现问题,你会确切地知道哪个端点被访问以及请求花费了多长时间。
错误处理可以防止你的 API 在出现意外情况时崩溃。相反,它会优雅地恢复并向客户端发送一条清晰的错误消息。