学习笔记,写到哪是哪。
接着上一篇的文章构建的项目:Go语学习笔记 - 项目规范结构调整 | Web框架Gin(三)_剑客阿良_ALiang的博客-CSDN博客
项目结构进一步调整为mvc结构,但还是需要加一些配置,比如跨域配置和全局异常捕获。
在项目开发中,某些非业务类的异常通常都会使用全局异常捕获的方法,简化代码量,下面我来调整一下之前的项目。
项目地址:github地址
跨域配置
在app/router文件夹下增加middlewares.go文件。
增加跨域支持方法,代码如下:
//跨域设置
func Cors() gin.HandlerFunc {
return func(c *gin.Context) {
method := c.Request.Method
origin := c.Request.Header.Get("Origin") //请求头部
if origin != "" {
c.Header("Access-Control-Allow-Origin", "*") // 可将将 * 替换为指定的域名
c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE, UPDATE")
c.Header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization")
c.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Cache-Control, Content-Language, Content-Type")
c.Header("Access-Control-Allow-Credentials", "true")
}
//允许类型校验
if method == "OPTIONS" {
c.JSON(http.StatusOK, "ok!")
}
defer func() {
if err := recover(); err != nil {
log.Logger.Error("HttpError", zap.Any("HttpError", err))
}
}()
c.Next()
}
}
全局捕获
在app/router文件夹下middlewares.go文件,增加全局捕获方法Recovery,代码如下。
//全局捕获
func Recovery(c *gin.Context) {
defer func() {
if r := recover(); r != nil {
log.Logger.Error("gin catch error: ", log.Any("gin catch error: ", r))
c.JSON(http.StatusOK, rsp.FailMsg("系统内部错误"))
}
}()
c.Next()
}
其中的rsp是返回结构体目录,在app/pojo下创建rsp目录,增加response_msg.go文件。
response_msg.go文件代码如下:
package rsp
type ResponseMsg struct {
Code int `json:"code"`
Msg string `json:"msg"`
Data interface{} `json:"data"`
}
func SuccessMsg(data interface{}) *ResponseMsg {
msg := &ResponseMsg{
Code: 0,
Msg: "SUCCESS",
Data: data,
}
return msg
}
func FailMsg(msg string) *ResponseMsg {
msgObj := &ResponseMsg{
Code: -1,
Msg: msg,
}
return msgObj
}
func FailCodeMsg(code int, msg string) *ResponseMsg {
msgObj := &ResponseMsg{
Code: code,
Msg: msg,
}
return msgObj
}
验证
app/router下的middlewares.go文件,完整代码如下:
package router
import (
"github.com/gin-gonic/gin"
"go.uber.org/zap"
"learn-gin/app/pojo/rsp"
"learn-gin/config/log"
"net/http"
)
//跨域设置
func Cors() gin.HandlerFunc {
return func(c *gin.Context) {
method := c.Request.Method
origin := c.Request.Header.Get("Origin") //请求头部
if origin != "" {
c.Header("Access-Control-Allow-Origin", "*") // 可将将 * 替换为指定的域名
c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE, UPDATE")
c.Header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization")
c.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Cache-Control, Content-Language, Content-Type")
c.Header("Access-Control-Allow-Credentials", "true")
}
//允许类型校验
if method == "OPTIONS" {
c.JSON(http.StatusOK, "ok!")
}
defer func() {
if err := recover(); err != nil {
log.Logger.Error("HttpError", zap.Any("HttpError", err))
}
}()
c.Next()
}
}
//全局捕获
func Recovery(c *gin.Context) {
defer func() {
if r := recover(); r != nil {
log.Logger.Error("gin catch error: ", log.Any("gin catch error: ", r))
c.JSON(http.StatusOK, rsp.FailMsg("系统内部错误"))
}
}()
c.Next()
}
main.go文件调整,代码如下:
package main
import (
"github.com/gin-gonic/gin"
"learn-gin/app/router"
"learn-gin/config/log"
"learn-gin/config/toml"
"net/http"
"time"
)
func main() {
log.InitLogger(toml.GetConfig().Log.Path, toml.GetConfig().Log.Level)
log.Logger.Info("hahahah")
log.Logger.Info("config", log.Any("config", toml.GetConfig()))
r := gin.Default()
r.Use(router.Cors())
r.Use(router.Recovery)
router.InitRouter(r)
s := &http.Server{
Addr: ":8080",
Handler: r,
ReadTimeout: 10 * time.Second,
WriteTimeout: 10 * time.Second,
MaxHeaderBytes: 1 << 20,
}
err := s.ListenAndServe()
if nil != err {
log.Logger.Error("server error", log.Any("serverError", err))
}
}
注意
1、在服务启动也调整了一下,不直接run。
2、通过r.Use方法,将跨域方法和全局异常监听加入启动项。
验证一下
在需要添加参数的请求,不添加后,会返回全局统一异常报文。
看一下日志
可以看到接口未处理的异常被全局捕获,返回统一的报文。
小结
现在项目看上去结构比较完整了,虽然一些常用的工具类还没有放进来,但是基本上可以作为开发样板服务。后面我想先把一些常用的工具类放进来,然后试着开始连接数据库,做一些基本业务功能。