错误处理和跨域

真实接口不能只返回 err.Error()

至少要保证:

  • 参数错误返回 400。
  • 未登录返回 401。
  • 没权限返回 403。
  • 找不到资源返回 404。
  • 服务端异常返回 500。

一、业务错误示例

先定义一个简单错误响应:

type ErrorResponse struct {
	Code    int    `json:"code"`
	Message string `json:"message"`
}

封装:

func Error(c *gin.Context, status int, message string) {
	c.JSON(status, ErrorResponse{
		Code:    status,
		Message: message,
	})
}

使用:

func getUser(c *gin.Context) {
	id := c.Param("id")
	if id == "" {
		Error(c, 400, "用户 ID 不能为空")
		return
	}

	Error(c, 404, "用户不存在")
}

二、Recovery

gin.Default() 默认带了 gin.Recovery()

它的作用是:接口发生 panic 时,不让整个服务退出,而是返回 500。

如果你使用 gin.New(),记得自己加:

router := gin.New()
router.Use(gin.Logger())
router.Use(gin.Recovery())

三、自定义 Recovery

需要统一返回 JSON 时,可以使用 gin.CustomRecovery

router.Use(gin.CustomRecovery(func(c *gin.Context, recovered any) {
	c.JSON(500, gin.H{
		"code":    500,
		"message": "服务器内部错误",
	})
}))

生产环境不要把 panic 细节直接返回给前端。

四、跨域是什么

当前端页面和后端接口不在同一个源时,浏览器会检查 CORS。

例如:

前端:http://localhost:5173
后端:http://localhost:8080

端口不同,也算不同源。

五、使用 gin-contrib/cors

Gin 本身不内置完整 CORS 配置,常用做法是使用 gin-contrib/cors

安装:

go get github.com/gin-contrib/cors

使用:

import (
	"time"

	"github.com/gin-contrib/cors"
	"github.com/gin-gonic/gin"
)

func main() {
	router := gin.Default()

	router.Use(cors.New(cors.Config{
		AllowOrigins:     []string{"http://localhost:5173"},
		AllowMethods:     []string{"GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"},
		AllowHeaders:     []string{"Origin", "Content-Type", "Authorization"},
		ExposeHeaders:    []string{"Content-Length"},
		AllowCredentials: true,
		MaxAge:           12 * time.Hour,
	}))

	router.Run(":8080")
}

不要在生产环境随便配置 AllowOrigins: []string{"*"},尤其是接口需要携带 Cookie 或认证信息时。