使用 `recover`
本课属于 Coddy GO 学习旅程的“逻辑与流程”单元。第 43 课,共 68 课。
虽然 panic 会立即停止程序,但 Go 提供了一种通过 recover 函数重新获得控制权的方法。recover 函数可以捕获 panic 并妥善处理,防止整个程序崩溃。
不过,recover 有一个非常具体的要求:它只能在延迟函数中使用。发生 panic 时,Go 会在程序终止前执行所有延迟函数,这让 recover 有机会拦截 panic:
func riskyFunction() {
defer func() {
if r := recover(); r != nil {
fmt.Println("Recovered from panic:", r)
}
}()
panic("something went wrong!")
}recover 函数会返回传递给 panic 的值。如果没有发生 panic,则返回 nil。这样你就可以检查是否发生了 panic,并采取适当的操作,例如记录错误或执行清理操作。
和 panic 一样,在 Go 中也应谨慎使用 recover。它最常见于 Web 服务器等场景,在这些场景中,你希望避免单个请求触发的 panic 导致整个服务器崩溃,让服务器可以继续处理其他请求。
挑战
简单构建一个 Web 服务器请求处理程序,使用 recover 优雅地处理 panic,防止整个服务器崩溃。本挑战将展示如何在延迟执行的函数中使用 recover 捕获 panic,并保持服务器稳定。
你将收到两个输入:
- 一个包含请求详情的字符串,格式为
"endpoint,method,action"(例如:"/api/users,GET,process") - 一个包含服务器配置的字符串,格式为
"server_name,max_requests"(例如:"WebServer,100")
你的任务是:
- 通过按逗号拆分第一个输入,获取 endpoint、method 和 action
- 通过按逗号拆分第二个输入,获取服务器名称和最大请求数
- 将最大请求数字符串转换为整数
- 创建一个名为
handleRequest的函数,将 endpoint、method、action 和服务器名称作为参数 - 在
handleRequest中添加一个延迟执行的函数,使用recover捕获任何 panic:- 如果恢复了 panic(
recover返回非 nil 值),打印:"Server [server_name] recovered from panic: [panic_value]" - 处理完 panic 后,打印:
"Request handling completed safely"
- 如果恢复了 panic(
- 在延迟执行的函数之后,根据 action 模拟请求处理:
- 如果 action 是
"process":打印"Processing [method] request to [endpoint]" - 如果 action 是
"panic_nil":打印"Attempting dangerous operation",然后调用panic("nil pointer access") - 如果 action 是
"panic_overflow":打印"Attempting resource allocation",然后调用panic("memory overflow") - 如果 action 是
"panic_timeout":打印"Attempting database connection",然后调用panic("connection timeout") - 对于其他任何 action:打印
"Unknown action: [action]",然后调用panic("invalid action")
- 如果 action 是
- 在 main 函数中,打印服务器启动消息:
"Starting [server_name] with max [max_requests] requests" - 使用解析后的参数调用
handleRequest函数 - 函数调用后,打印服务器状态:
"Server [server_name] is still running" - 最后,打印摘要:
"Server Summary:""Name: [server_name]""Max Requests: [max_requests]""Last Request: [method] [endpoint]""Action Performed: [action]""Status: Operational"
使用 strings 包按逗号拆分输入字符串,并使用 strconv 包将最大请求数字符串转换为整数。本挑战将展示 recover 如何帮助服务器优雅地处理意外的 panic,防止单个请求失败导致整个系统停止运行。
亲手试试
package main
import (
"fmt"
"strconv"
"strings"
)
func main() {
// 读取输入
var requestDetails string
var serverConfig string
fmt.Scanln(&requestDetails)
fmt.Scanln(&serverConfig)
// 解析请求详情
requestParts := strings.Split(requestDetails, ",")
endpoint := requestParts[0]
method := requestParts[1]
action := requestParts[2]
// 解析服务器配置
configParts := strings.Split(serverConfig, ",")
serverName := configParts[0]
maxRequests, _ := strconv.Atoi(configParts[1])
// TODO: 在下方编写代码
// 创建带有 recover 机制的 handleRequest 函数
// 输出服务器启动信息
// 调用 handleRequest 函数
// 输出服务器状态和摘要
}这节课包含一个小测验。开始学习即可作答,并记录你的进度。
逻辑与流程中的所有课
自己练习: Go 在线编译器