W3Cschool
恭喜您成為首批注冊用戶
獲得88經(jīng)驗(yàn)值獎(jiǎng)勵(lì)
目前大多數(shù)Golang的第三方?WebServer
?庫均沒有默認(rèn)對?HTTP
?請求處理過程中產(chǎn)生的異常進(jìn)行捕獲,輕者錯(cuò)誤產(chǎn)生后無法記錄到日志造成排查錯(cuò)困難,重則異常造成進(jìn)程直接崩潰,服務(wù)不可用。
當(dāng)你選擇?goframe
?,你很幸運(yùn)。裸奔誰都會(huì),但作為一款企業(yè)級的基礎(chǔ)開發(fā)框架,對嚴(yán)謹(jǐn)及安全性的要求大于性能,因此默認(rèn)情況下,執(zhí)行過程中產(chǎn)生的?panic
?是有被?Server
?自動(dòng)捕獲的,產(chǎn)生?panic
?時(shí)當(dāng)前執(zhí)行流程會(huì)立即中止,但是絕對不會(huì)影響進(jìn)程直接崩潰。
?HTTP
?執(zhí)行流程中產(chǎn)生?panic
?異常時(shí),默認(rèn)處理是記錄到?Server
?的日志文件中。當(dāng)然,開發(fā)者也可以通過注冊中間件方式手動(dòng)捕獲,然后自定義相關(guān)的錯(cuò)誤處理。這一操作其實(shí)在中間件章節(jié)的示例中也有介紹,我們這里來再仔細(xì)說明下。
異常的捕獲我們通過?Request
?對象中的?GetError
?方法獲取。
開發(fā)者不能通過?recover
?方法來捕獲異常,因?yàn)?goframe
?框架的?Server
?已經(jīng)做了捕獲,并且為保證默認(rèn)情況下異常不會(huì)引起進(jìn)程崩潰,因此不會(huì)再次往上拋異常。
// GetError returns the error occurs in the procedure of the request.
// It returns nil if there's no error.
func (r *Request) GetError() error
該方法往往使用在流程控制組件中,如后置中間件或者?HOOK
?鉤子方法中。
我們這里使用一個(gè)全局的后置中間件來捕獲異常,當(dāng)異常產(chǎn)生后,捕獲并寫入到指定的日志文件中,返回固定友好的提示信息,避免敏感的報(bào)錯(cuò)信息暴露給調(diào)用端。
需要注意的是:
Server
?依舊會(huì)打印到?Server
?自己的錯(cuò)誤日志文件中。由開發(fā)者調(diào)用日志接口方法輸出的日志屬于業(yè)務(wù)日志(與業(yè)務(wù)相關(guān)),而?Server
?自行管理的日志屬于服務(wù)日志(類似于?nginx
?的?error.log
?)。
goframe
?框架大部分的底層錯(cuò)誤都包含有錯(cuò)誤時(shí)的堆棧信息,如果對于?error
?的具體堆棧信息感興趣(具體調(diào)用鏈、報(bào)錯(cuò)文件路徑、源碼行號等),可以使用?gerror
?來獲取。如果異常包含堆棧信息,默認(rèn)情況下會(huì)打印到?Server
?的?error
?日志文件中。package main
import (
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/net/ghttp"
)
func MiddlewareErrorHandler(r *ghttp.Request) {
r.Middleware.Next()
if err := r.GetError(); err != nil {
// 記錄到自定義錯(cuò)誤日志文件
g.Log("exception").Error(err)
//返回固定的友好信息
r.Response.ClearBuffer()
r.Response.Writeln("服務(wù)器居然開小差了,請稍后再試吧!")
}
}
func main() {
s := g.Server()
s.Use(MiddlewareErrorHandler)
s.Group("/api.v2", func(group *ghttp.RouterGroup) {
group.ALL("/user/list", func(r *ghttp.Request) {
panic("db error: sql is xxxxxxx")
})
})
s.SetPort(8199)
s.Run()
}
執(zhí)行后,我們通過?curl
?工具來試試吧:
$ curl -v "http://127.0.0.1:8199/api.v2/user/list"
> GET /api.v2/user/list HTTP/1.1
> Host: 127.0.0.1:8199
> User-Agent: curl/7.61.1
> Accept: */*
>
< HTTP/1.1 500 Internal Server Error
< Server: GF HTTP Server
< Date: Sun, 19 Jul 2020 07:44:30 GMT
< Content-Length: 52
< Content-Type: text/plain; charset=utf-8
<
服務(wù)器居然開小差了,請稍后再試吧!
?WebServer
?本身在捕獲異常時(shí),如果拋出的異常信息并不包含堆棧內(nèi)容,那么?WebServer
?會(huì)自動(dòng)獲取拋出異常位點(diǎn)(即?panic
?的位置)的堆棧并創(chuàng)建一個(gè)新的包含該堆棧信息的錯(cuò)誤對象。我們來看一個(gè)示例。
package main
import (
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/net/ghttp"
)
func MiddlewareErrorHandler(r *ghttp.Request) {
r.Middleware.Next()
if err := r.GetError(); err != nil {
r.Response.ClearBuffer()
r.Response.Writef("%+v", err)
}
}
func main() {
s := g.Server()
s.Use(MiddlewareErrorHandler)
s.Group("/api.v2", func(group *ghttp.RouterGroup) {
group.ALL("/user/list", func(r *ghttp.Request) {
panic("db error: sql is xxxxxxx")
})
})
s.SetPort(8199)
s.Run()
}
可以看到,我們通過?%+v
?的格式化打印來獲取異常錯(cuò)誤中的堆棧信息。執(zhí)行后,我們通過?curl
?工具來測試下:
$ curl "http://127.0.0.1:8199/api.v2/user/list"
db error: sql is xxxxxxx
1. db error: sql is xxxxxxx
1). main.main.func1.1
/Users/john/Workspace/Go/GOPATH/src/github.com/gogf/gf/.example/other/test.go:25
2). github.com/gogf/gf/v2/net/ghttp.(*middleware).Next.func1.8
/Users/john/Workspace/Go/GOPATH/src/github.com/gogf/gf/v2/net/ghttp/ghttp_request_middleware.go:111
3). github.com/gogf/gf/v2/net/ghttp.niceCallFunc
/Users/john/Workspace/Go/GOPATH/src/github.com/gogf/gf/v2/net/ghttp/ghttp_func.go:46
4). github.com/gogf/gf/v2/net/ghttp.(*middleware).Next.func1
/Users/john/Workspace/Go/GOPATH/src/github.com/gogf/gf/v2/net/ghttp/ghttp_request_middleware.go:110
5). github.com/gogf/gf/v2/util/gutil.TryCatch
/Users/john/Workspace/Go/GOPATH/src/github.com/gogf/gf/v2/util/gutil/gutil.go:46
6). github.com/gogf/gf/v2/net/ghttp.(*middleware).Next
/Users/john/Workspace/Go/GOPATH/src/github.com/gogf/gf/v2/net/ghttp/ghttp_request_middleware.go:47
7). main.MiddlewareErrorHandler
/Users/john/Workspace/Go/GOPATH/src/github.com/gogf/gf/.example/other/test.go:10
8). github.com/gogf/gf/v2/net/ghttp.(*middleware).Next.func1.9
/Users/john/Workspace/Go/GOPATH/src/github.com/gogf/gf/v2/net/ghttp/ghttp_request_middleware.go:117
9). github.com/gogf/gf/v2/net/ghttp.niceCallFunc
/Users/john/Workspace/Go/GOPATH/src/github.com/gogf/gf/v2/net/ghttp/ghttp_func.go:46
10). github.com/gogf/gf/v2/net/ghttp.(*middleware).Next.func1
/Users/john/Workspace/Go/GOPATH/src/github.com/gogf/gf/v2/net/ghttp/ghttp_request_middleware.go:116
11). github.com/gogf/gf/v2/util/gutil.TryCatch
/Users/john/Workspace/Go/GOPATH/src/github.com/gogf/gf/v2/util/gutil/gutil.go:46
12). github.com/gogf/gf/v2/net/ghttp.(*middleware).Next
/Users/john/Workspace/Go/GOPATH/src/github.com/gogf/gf/v2/net/ghttp/ghttp_request_middleware.go:47
13). github.com/gogf/gf/v2/net/ghttp.(*Server).ServeHTTP
/Users/john/Workspace/Go/GOPATH/src/github.com/gogf/gf/v2/net/ghttp/ghttp_server_handler.go:122
如果拋出的異常是一個(gè)通過?gerror
?組件的錯(cuò)誤對象,或者實(shí)現(xiàn)堆棧打印接口的錯(cuò)誤對象,由于該異常的錯(cuò)誤對象已經(jīng)包含了詳細(xì)的堆棧信息,那么?WebServer
?將會(huì)直接返回該錯(cuò)誤對象,不會(huì)自動(dòng)創(chuàng)建錯(cuò)誤對象。我們來看一個(gè)示例。
package main
import (
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/net/ghttp"
)
func MiddlewareErrorHandler(r *ghttp.Request) {
r.Middleware.Next()
if err := r.GetError(); err != nil {
r.Response.ClearBuffer()
r.Response.Writef("%+v", err)
}
}
func DbOperation() error {
// ...
return gerror.New("DbOperation error: sql is xxxxxxx")
}
func UpdateData() {
err := DbOperation()
if err != nil {
panic(gerror.Wrap(err, "UpdateData error"))
}
}
func main() {
s := g.Server()
s.Use(MiddlewareErrorHandler)
s.Group("/api.v2", func(group *ghttp.RouterGroup) {
group.ALL("/user/list", func(r *ghttp.Request) {
UpdateData()
})
})
s.SetPort(8199)
s.Run()
}
執(zhí)行后,我們通過?curl
?工具來測試下:
$ curl "http://127.0.0.1:8199/api.v2/user/list"
UpdateData error: DbOperation error: sql is xxxxxxx
1. UpdateData error
1). main.UpdateData
/Users/john/Workspace/Go/GOPATH/src/github.com/gogf/gf/.example/other/test.go:25
2). main.main.func1.1
/Users/john/Workspace/Go/GOPATH/src/github.com/gogf/gf/.example/other/test.go:34
3). github.com/gogf/gf/v2/net/ghttp.(*middleware).Next.func1.8
/Users/john/Workspace/Go/GOPATH/src/github.com/gogf/gf/v2/net/ghttp/ghttp_request_middleware.go:111
4). github.com/gogf/gf/v2/net/ghttp.niceCallFunc
/Users/john/Workspace/Go/GOPATH/src/github.com/gogf/gf/v2/net/ghttp/ghttp_func.go:46
5). github.com/gogf/gf/v2/net/ghttp.(*middleware).Next.func1
/Users/john/Workspace/Go/GOPATH/src/github.com/gogf/gf/v2/net/ghttp/ghttp_request_middleware.go:110
6). github.com/gogf/gf/v2/util/gutil.TryCatch
/Users/john/Workspace/Go/GOPATH/src/github.com/gogf/gf/v2/util/gutil/gutil.go:46
7). github.com/gogf/gf/v2/net/ghttp.(*middleware).Next
/Users/john/Workspace/Go/GOPATH/src/github.com/gogf/gf/v2/net/ghttp/ghttp_request_middleware.go:47
8). main.MiddlewareErrorHandler
/Users/john/Workspace/Go/GOPATH/src/github.com/gogf/gf/.example/other/test.go:10
9). github.com/gogf/gf/v2/net/ghttp.(*middleware).Next.func1.9
/Users/john/Workspace/Go/GOPATH/src/github.com/gogf/gf/v2/net/ghttp/ghttp_request_middleware.go:117
10). github.com/gogf/gf/v2/net/ghttp.niceCallFunc
/Users/john/Workspace/Go/GOPATH/src/github.com/gogf/gf/v2/net/ghttp/ghttp_func.go:46
11). github.com/gogf/gf/v2/net/ghttp.(*middleware).Next.func1
/Users/john/Workspace/Go/GOPATH/src/github.com/gogf/gf/v2/net/ghttp/ghttp_request_middleware.go:116
12). github.com/gogf/gf/v2/util/gutil.TryCatch
/Users/john/Workspace/Go/GOPATH/src/github.com/gogf/gf/v2/util/gutil/gutil.go:46
13). github.com/gogf/gf/v2/net/ghttp.(*middleware).Next
/Users/john/Workspace/Go/GOPATH/src/github.com/gogf/gf/v2/net/ghttp/ghttp_request_middleware.go:47
14). github.com/gogf/gf/v2/net/ghttp.(*Server).ServeHTTP
/Users/john/Workspace/Go/GOPATH/src/github.com/gogf/gf/v2/net/ghttp/ghttp_server_handler.go:122
2. DbOperation error: sql is xxxxxxx
1). main.DbOperation
/Users/john/Workspace/Go/GOPATH/src/github.com/gogf/gf/.example/other/test.go:19
2). main.UpdateData
/Users/john/Workspace/Go/GOPATH/src/github.com/gogf/gf/.example/other/test.go:23
3). main.main.func1.1
/Users/john/Workspace/Go/GOPATH/src/github.com/gogf/gf/.example/other/test.go:34
4). github.com/gogf/gf/v2/net/ghttp.(*middleware).Next.func1.8
/Users/john/Workspace/Go/GOPATH/src/github.com/gogf/gf/v2/net/ghttp/ghttp_request_middleware.go:111
5). github.com/gogf/gf/v2/net/ghttp.niceCallFunc
/Users/john/Workspace/Go/GOPATH/src/github.com/gogf/gf/v2/net/ghttp/ghttp_func.go:46
6). github.com/gogf/gf/v2/net/ghttp.(*middleware).Next.func1
/Users/john/Workspace/Go/GOPATH/src/github.com/gogf/gf/v2/net/ghttp/ghttp_request_middleware.go:110
7). github.com/gogf/gf/v2/util/gutil.TryCatch
/Users/john/Workspace/Go/GOPATH/src/github.com/gogf/gf/v2/util/gutil/gutil.go:46
8). github.com/gogf/gf/v2/net/ghttp.(*middleware).Next
/Users/john/Workspace/Go/GOPATH/src/github.com/gogf/gf/v2/net/ghttp/ghttp_request_middleware.go:47
9). main.MiddlewareErrorHandler
/Users/john/Workspace/Go/GOPATH/src/github.com/gogf/gf/.example/other/test.go:10
10). github.com/gogf/gf/v2/net/ghttp.(*middleware).Next.func1.9
/Users/john/Workspace/Go/GOPATH/src/github.com/gogf/gf/v2/net/ghttp/ghttp_request_middleware.go:117
11). github.com/gogf/gf/v2/net/ghttp.niceCallFunc
/Users/john/Workspace/Go/GOPATH/src/github.com/gogf/gf/v2/net/ghttp/ghttp_func.go:46
12). github.com/gogf/gf/v2/net/ghttp.(*middleware).Next.func1
/Users/john/Workspace/Go/GOPATH/src/github.com/gogf/gf/v2/net/ghttp/ghttp_request_middleware.go:116
13). github.com/gogf/gf/v2/util/gutil.TryCatch
/Users/john/Workspace/Go/GOPATH/src/github.com/gogf/gf/v2/util/gutil/gutil.go:46
14). github.com/gogf/gf/v2/net/ghttp.(*middleware).Next
/Users/john/Workspace/Go/GOPATH/src/github.com/gogf/gf/v2/net/ghttp/ghttp_request_middleware.go:47
15). github.com/gogf/gf/v2/net/ghttp.(*Server).ServeHTTP
/Users/john/Workspace/Go/GOPATH/src/github.com/gogf/gf/v2/net/ghttp/ghttp_server_handler.go:122
Copyright©2021 w3cschool編程獅|閩ICP備15016281號-3|閩公網(wǎng)安備35020302033924號
違法和不良信息舉報(bào)電話:173-0602-2364|舉報(bào)郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號
聯(lián)系方式:
更多建議: