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)
...
}