面试题答案
一键面试-
设计思路:
- 中间件(Middleware):使用中间件来捕获处理函数中抛出的异常。这样可以在不修改每个处理函数具体逻辑的情况下,统一处理异常。
- 自定义错误类型:定义自定义错误类型,以便区分业务逻辑错误和系统错误,并根据不同类型返回不同的HTTP状态码。
- 日志记录:在捕获异常时记录详细的日志,方便调试和排查问题。
-
关键代码示例:
package main
import (
"encoding/json"
"fmt"
"log"
"net/http"
)
// 自定义错误类型
type BusinessError struct {
ErrorMessage string `json:"error_message"`
}
func (be BusinessError) Error() string {
return be.ErrorMessage
}
// 异常处理中间件
func errorHandler(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
defer func() {
if err := recover(); err!= nil {
// 记录异常日志
log.Printf("Panic occurred: %v", err)
var statusCode int
var errorMsg string
switch err := err.(type) {
case BusinessError:
statusCode = http.StatusBadRequest
errorMsg = err.Error()
default:
statusCode = http.StatusInternalServerError
errorMsg = "Internal Server Error"
}
w.WriteHeader(statusCode)
response := map[string]string{"error": errorMsg}
json.NewEncoder(w).Encode(response)
}
}()
next.ServeHTTP(w, r)
})
}
// 模拟业务处理函数
func handleRequest(w http.ResponseWriter, r *http.Request) {
// 模拟业务逻辑错误
if r.URL.Query().Get("error") == "business" {
panic(BusinessError{ErrorMessage: "Business logic error"})
}
// 模拟系统错误
if r.URL.Query().Get("error") == "system" {
panic(fmt.Errorf("System error"))
}
w.Write([]byte("Request processed successfully"))
}
func main() {
http.Handle("/", errorHandler(http.HandlerFunc(handleRequest)))
log.Fatal(http.ListenAndServe(":8080", nil))
}
在上述代码中:
BusinessError
是自定义的业务逻辑错误类型。errorHandler
是异常处理中间件,使用defer
和recover
来捕获处理函数中抛出的异常。根据异常类型设置不同的HTTP状态码,并返回相应的错误信息。同时记录异常日志。handleRequest
是模拟的业务处理函数,根据URL参数模拟不同类型的异常。- 在
main
函数中,将errorHandler
应用到handleRequest
上,这样在处理HTTP请求时,如果发生异常,errorHandler
会捕获并处理。