面试题答案
一键面试1. 定义统一的错误类型
在Go中,可以定义一个基础的错误类型,并在此基础上衍生出具体的业务错误类型。例如:
package main
import (
"errors"
)
// 基础错误类型
var ErrBase = errors.New("base error")
// 具体业务错误类型
var ErrSpecific = errors.New("specific business error")
这样在不同微服务中遇到相同类型的错误时,可以统一处理。
2. 在微服务间传递错误
- HTTP服务:在HTTP服务中,可以根据错误类型设置合适的HTTP状态码。例如,使用
net/http
库:
package main
import (
"fmt"
"net/http"
)
func handler(w http.ResponseWriter, r *http.Request) {
err := someFunction()
if err != nil {
if errors.Is(err, ErrSpecific) {
http.Error(w, "Specific error", http.StatusBadRequest)
} else {
http.Error(w, "Internal error", http.StatusInternalServerError)
}
return
}
fmt.Fprintf(w, "Success")
}
func someFunction() error {
// 模拟返回错误
return ErrSpecific
}
- RPC服务:如果使用gRPC等RPC框架,同样可以在响应中设置错误码和错误信息。例如,在gRPC服务中:
package main
import (
"context"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
func (s *Server) SomeRPCFunction(ctx context.Context, req *Request) (*Response, error) {
err := someFunction()
if err != nil {
if errors.Is(err, ErrSpecific) {
return nil, status.Error(codes.InvalidArgument, "Specific error")
} else {
return nil, status.Error(codes.Internal, "Internal error")
}
}
return &Response{}, nil
}
3. 错误记录
使用Go标准库中的log
包进行错误记录。可以创建一个全局的日志记录器,在错误发生时记录详细信息。例如:
package main
import (
"log"
)
func main() {
err := someFunction()
if err != nil {
log.Printf("Error occurred: %v", err)
}
}
func someFunction() error {
// 模拟返回错误
return ErrSpecific
}
对于更复杂的日志需求,可以使用第三方库如zap
,它提供了更灵活和高效的日志记录方式。例如:
package main
import (
"go.uber.org/zap"
)
func main() {
logger, _ := zap.NewProduction()
defer logger.Sync()
err := someFunction()
if err != nil {
logger.Error("Error occurred", zap.Error(err))
}
}
func someFunction() error {
// 模拟返回错误
return ErrSpecific
}
4. 编码与解码错误
在微服务间进行数据交换时,使用标准库中的编码和解码工具(如encoding/json
)。在编码和解码过程中捕获错误,并进行合适的处理。例如:
package main
import (
"encoding/json"
"fmt"
)
type Data struct {
Field string `json:"field"`
}
func main() {
data := Data{Field: "value"}
jsonData, err := json.Marshal(data)
if err != nil {
fmt.Printf("Encoding error: %v", err)
return
}
var decodedData Data
err = json.Unmarshal(jsonData, &decodedData)
if err != nil {
fmt.Printf("Decoding error: %v", err)
return
}
fmt.Printf("Decoded data: %+v", decodedData)
}
5. 性能与可维护性
- 性能:避免在错误处理路径上进行复杂的计算和不必要的操作。例如,在日志记录时,只记录必要的信息,避免大量格式化操作。
- 可维护性:保持错误处理逻辑的一致性。在每个微服务中都按照统一的策略处理错误,这样在排查问题时可以快速定位。同时,通过清晰的错误类型定义和注释,使代码更易于理解和维护。