go从0到1项目实战体系三十六:三层架构的error错误的处理

本文主要讨论了在Gin框架下,如何优化数据库操作(如BookService中的BookDetail和BookList方法),处理SQL执行错误,以及在router中处理参数类型错误和ServiceHelper中添加异常处理,确保API返回正确的HTTP状态码和错误信息。
摘要由CSDN通过智能技术生成

1. DB:

1.1 返回空book实体:

(1). 现象:

http://localhost:8080/v1/book,如果访问不存在的记录,返回一个空的book实体:
{
	"ResultData":
	{
		"BookID":0,"BookName":"","BookIntr":"","BookPrice1":0,"BookPrice2":0,"BookAuthor":"","BookPress":"","BookDate":"","BookKind":0,"BookKindStr":""
	}
}

(2). 优化(BsyErp\Contract\App\Services\BookService.go):

// 增加两个值返回
func(s *BookService) BookDetail(req *BookDetailRequest) (*Models.Books, error) {
	book := &Models.Books{}
	if Init.GetDB().Find(book, req.BookID).RowsAffected != 1 {
		// 增加两个值返回
		return nil, fmt.Errorf("no body")
	}
	// 增加两个值返回
	return book, nil
}:. 增加返回参数error.. 同步修改BsyErp\Contract\App\Services\BookEndpoint.go代码:
func BookDetailEndPoint(book *BookService) Lib.Endpoint {
	return func(ctx context.Context, request interface{}) (interface{}, error) {
		req := request.(*BookDetailRequest)
		// 这里增加err,下面传err
		result, err := book.BookDetail(req)
		return &BookResponse{Result: result}, err
	}
}

1.2 sql执行错误:

(1). 现象:
BsyErp\Contract\App\Services\BookService.go:

如果下面语句sql执行报错,连接池出现错误.怎么处理?
Init.GetDB().Limit(req.Page).Offset(req.Size).Order("book_id desc").Find(books)

(2). 优化(BsyErp\Contract\App\Services\BookService.go):

// 增加两个值返回
func(s *BookService) BookList(req  *BookListRequest) (*Models.BooksList, error) {
	books := &Models.BooksList{}
	err := Init.GetDB().Limit(req.Page).Offset(req.Size).Order("book_id desc").Find(books).Error
	if err != nil {
		return nil, err
	}
	return books, nil
}:. 增加返回参数error. 同步修改BsyErp\Contract\App\Services\BookEndpoint.go的BookListEndPoint代码.

2. router:

1.2 参数类型不同报错处理:

(1). 现象:

http://localhost:8080/v1/books?page=abc&size=2,会报错:. [GIN-debug][WARNING]Headers were already written.Wanted to override status code 400 with 500
   a. 头已经设置好了,想要把500来修改400.
   b. 查看浏览器network,这个请求显示:Status Code: 400 Bad Request
   c. 代码中写了是500返回,但是实际上还是400返回.. {"ResultData":"参数错误:strconv.ParseInt: parsing \"acb\": invalid syntax","ServerNo":"SN500"}

(2). 查看源码位置:

. BsyErp\Contract\App\Services\BookTransport.go:
   req := &BookListRequest{}
   err := context.BindQuery(req)   // 点击BindQuery跳到下面. GOPATH\pkg\mod\github.com\gin-gonic\gin@v1.5.0\context.go:
   // BindQuery is a shortcut for c.MustBindWith(obj, binding.Query).
   func (c *Context) BindQuery(obj interface{}) error {
      return c.MustBindWith(obj, binding.Query)    // 点击MustBindWith跳到本文件下面
   }

   // MustBindWith binds the passed struct pointer using the specified binding engine.
   // It will abort the request with HTTP 400 if any error occurs.
   // See the binding package.
   func (c *Context) MustBindWith(obj interface{}, b binding.Binding) error {
	  if err := c.ShouldBindWith(obj, b); err != nil {
		// 点击StatusBadRequest跳到下面文件
	 	c.AbortWithError(http.StatusBadRequest, err).SetType(ErrorTypeBind) // nolint: errcheck
		return err
	  }
	  return nil
   }. GOROOT\src\net\http\status.go:
   StatusBadRequest = 400 // RFC 7231, 6.5.1

(3). 优化(BsyErp\Contract\App\Services\BookTransport.go):

req := &BookListRequest{}
err := context.ShouldBindQuery(req):. 访问时,网络提示:Status Code: 500 Internal Server Error.

3. ServiceHelper接收手动抛错:

(1). 现象:

. 如果代码有panic,RegisterHandler中的err是接收不到的.. RegisterHandler就有点像中间件,后面还可以扩展自定义的函数式中间件,并且是与框架无关的.

(2). 优化(BsyErp\Contract\App\Lib\ServiceHelper.go):

. 随便在三个函数中写一段:
   panic("系统错误:请执行!"). 增加defer()异常处理:
return func(context *gin.Context) {
	// 后面可以优化成装饰器加载进来
	defer func(){
		if err := recover(); err != nil {
			// mismatched types string and interface{}
			context.JSON(http.StatusInternalServerError, gin.H{"ServerNo": "SN500", "ResultData": fmt.Sprint(err)})
			return
		}
	}()
	// 获取参数
	req, err := encodeFunc(context)
	...
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值