上文《Go语言Web开发系列(十四)Gin web封装统一返回结构体》我们统一封装了结构返回体。但是在代码里面我们可以看到很多的err判断,此时的话,我们一般希望有一个地方能统一处理这种error,并且返回统一的结构体。所以这里我们演示下在Gin web框架中处理全局异常。
这里处理全局异常比较简单,我们定义一个中间件即可,例如:
func Recover(c *gin.Context) { defer func() { if err := recover(); err != nil { // 返回统一的Json风格 Error(c, 500, err) //终止后续操作 c.Abort() } }() //继续操作 c.Next() }
这个中间件的话主要是结合panic来使用的,当系统出现recover的时候,我们就获取到对应的错误信息,然后组装成统一的json返回给前台。
在gin里面这里的中间件是全局的,所以我们使用:
router.Use(Recover)
就可以了,在代码里面只要出现error,我们就全部使用panic来处理,例如:
if err != nil { panic(err.Error()) }
这里我们演示一下,把登录的接口查询的sql语句里面的表修改为users1,但是我们数据库是不存在users1表的,所以这里会直接报错的,示例图如下:
然后我们把项目启动起来,登录一下,就可以看到错误信息返回了:
是不是很简单?
备注:
1、这里处理全局异常主要是使用中间件来实现的。 2、所有的error都需要使用panic函数来处理。 3、把原始的err错误提示字符串传递给panic。
最后我们附上修改后的完整代码:
// demo1 project main.go package main import ( "database/sql" "fmt" "log" "net/http" "time" "github.com/gin-gonic/gin" _ "github.com/go-sql-driver/mysql" ) type Users struct { Id int Name string NickName string } /* * 创建数据库连接 */ func connectToDatabase() (*sql.DB, error) { db, err := sql.Open("mysql", "root:123456@tcp(192.168.31.217:33306)/test") if err != nil { return nil, err } db.SetConnMaxLifetime(time.Second * 3600 * 8) db.SetMaxOpenConns(10) db.SetMaxIdleConns(10) err = db.Ping() if err != nil { return nil, err } return db, nil } func main() { //创建数据库连接 db, err := connectToDatabase() if err != nil { panic(err) } //程序关闭的时候需要关闭掉数据库连接 defer db.Close() router := gin.Default() router.Use(Recover) //用户登录 router.POST("/login", func(c *gin.Context) { username := c.PostForm("username") password := c.PostForm("password") log.Println("获取到的用户名和密码是:", username, password) rows, err := db.Query("SELECT id FROM users1 WHERE username = ? and password = ?", username, password) if err != nil { panic(err.Error()) } defer rows.Columns() if rows.Next() == true { Ok(c, 200, "登录成功", nil) } else { Error(c, 400, "用户名或者密码不正确") } }) //用户注册 router.POST("/register", func(c *gin.Context) { username := c.PostForm("username") password := c.PostForm("password") nickname := c.PostForm("nickname") log.Println("获取到的用户名和密码是:", username, password) inserSql := "insert into users(username,password,nickname) values(?,?,?)" // 创建事务 tx, err := db.Begin() if err != nil { panic(err) } // 执行插入语句 _, err = tx.Exec(inserSql, username, password, nickname) //value输入具体的值 if err != nil { panic(err) } // 提交事务 err = tx.Commit() if err != nil { panic(err) } Ok(c, 200, "注册成功", nil) }) //获取用户信息 router.POST("/getUinfo/:username", func(c *gin.Context) { username := c.Param("username") var user Users querySql := "SELECT id, username, nickname FROM users WHERE username = ?" err = db.QueryRow(querySql, username).Scan(&user.Id, &user.Name, &user.NickName) if err != nil { panic(err) } Ok(c, 200, "登录成功", user) }) //修改用户信息 router.POST("/updateUinfo", func(c *gin.Context) { username := c.PostForm("username") nickname := c.PostForm("nickname") updateSql := "update users set nickname= ? WHERE username = ?" _, err = db.Exec(updateSql, nickname, username) if err != nil { panic(err) } Ok(c, 200, "修改成功", nil) }) //删除用户信息 router.POST("/deleteU/:username", func(c *gin.Context) { username := c.Param("username") updateSql := "delete from users WHERE username = ?" _, err = db.Exec(updateSql, username) if err != nil { panic(err) } Ok(c, 200, "删除成功", nil) }) router.Run(":9000") } func Error(c *gin.Context, code int, msg any) { c.JSON(http.StatusOK, gin.H{ "code": code, "msg": msg, }) } func Ok(c *gin.Context, code int, msg string, data any) { c.JSON(http.StatusOK, gin.H{ "code": code, "msg": msg, "data": data, }) } func Recover(c *gin.Context) { defer func() { if err := recover(); err != nil { // 返回统一的Json风格 Error(c, 500, err) //终止后续操作 c.Abort() } }() //继续操作 c.Next() }
还没有评论,来说两句吧...