geektutu / blog

极客兔兔的博客,Coding Coding 创建有趣的开源项目。
https://geektutu.com
Apache License 2.0
167 stars 21 forks source link

Go语言动手写Web框架 - Gee第六天 错误恢复(Panic Recover) | 极客兔兔 #55

Open geektutu opened 4 years ago

geektutu commented 4 years ago

https://geektutu.com/post/gee-day7.html

7天用 Go语言 从零实现Web框架教程(7 days implement golang web framework from scratch tutorial),用 Go语言/golang 动手写Web框架,从零实现一个Web框架,以 Gin 为原型从零设计一个Web框架。本文介绍了如何为Web框架增加错误处理机制。

yywwann commented 4 years ago

r := gee.Default() 是怎么回事

geektutu commented 4 years ago

r := gee.Default() 是怎么回事

gee.go#L40 默认实例使用 LoggerRecovery 中间件。

// gee.go
// Default use Logger() & Recovery middlewares
func Default() *Engine {
    engine := New()
    engine.Use(Logger(), Recovery())
    return engine
}
ayuayue commented 4 years ago

这是什么问题 2020/04/14 22:21:07 Router GET - / 2020/04/14 22:21:07 Router GET - /panic 2020/04/14 22:21:14 http: panic serving [::1]:7184: runtime error: index out of range [100] with length 1 goroutine 8 [running]: net/http.(conn).serve.func1(0xc00005b220) c:/go/src/net/http/server.go:1767 +0x140 panic(0x7cd780, 0xc0000e6020) c:/go/src/runtime/panic.go:679 +0x1c0 main.main.func2(0xc0000f6000) E:/Github/go-web/main.go:101 +0x1d gee.(Context).Next(0xc0000f6000) E:/Github/go-web/gee/context.go:47 +0x45 gee.(router).handle(0xc000034be0, 0xc0000f6000) E:/Github/go-web/gee/router.go:92 +0x153 gee.(Engine).ServeHTTP(0xc00003e340, 0x884d80, 0xc0000f2000, 0xc0000dc100) E:/Github/go-web/gee/gee.go:140 +0x310 net/http.serverHandler.ServeHTTP(0xc0000c6000, 0x884d80, 0xc0000f2000, 0xc0000dc100) c:/go/src/net/http/server.go:2802 +0xab net/http.(conn).serve(0xc00005b220, 0x885380, 0xc0000de000) c:/go/src/net/http/server.go:1890 +0x87c created by net/http.(Server).Serve c:/go/src/net/http/server.go:2927 +0x395 exit status 2

ayuayue commented 4 years ago

代码一样,模版那一章css引入也失败了,template模版怎么解析go的切片变量

armstrong-liu commented 4 years ago

在添加Recovery中间件之前,通过访问越界下标的数组产生panic,但是web服务本身没有被down掉(崩溃),还可以继续处理正常的请求。所以有个疑问:panic是否会造成web服务的崩溃?

go版本:go1.13.5

geektutu commented 4 years ago

@ayuayue 这个错误是故意设计的,下标越界触发panic。

geektutu commented 4 years ago

@armstrong-liu net/http 的源码中,也使用了 recovery ,所以一般不会导致web服务崩溃,即其他请求不受影响。所以 Recovery 中间件在这里的作用还是保证所有请求都能正常响应,否则,panic 之后,就没回应了。之前没考虑到 net/http 内部实现这一点,文章内容有歧义,感谢你指出问题。

ayuayue commented 4 years ago

@geektutu @ayuayue 这个错误是故意设计的,下标越界触发panic。

触发了panic,其他路由可以正常返回,但是触发panic没有返回json,正常吗

SourceLink commented 4 years ago

收益匪浅, 感谢博主

geektutu commented 4 years ago

@SourceLink 很高兴对你有帮助~

xx444812313 commented 4 years ago

收获很多,对golang语言和gin框架熟悉程度加深,感谢博主😘😘😘

woshihuo12 commented 4 years ago

感谢楼主的无私奉献

ppd0705 commented 4 years ago

跟着实现了一遍,还是有一点点成就感的。感谢tutu的精心分享!

wings-xue commented 3 years ago

recorve 为什么一定要有 c.Next()? 没有就会报panic

zhcoders commented 3 years ago

@wings-xue recorve 为什么一定要有 c.Next()? 没有就会报panic

因为defer recover机制只能针对于当前函数以及直接调用的函数可能参数的panic,所以在Recovery里面的c.Next()会执行下面这个handler

func(c *gee.Context) {
        names := []string{"geektutu"}
        c.String(http.StatusOK, names[100])
}

从而捕获到panic并恢复 如果没有c.Next(),则handler不是Recovery直接调用的函数,无法recover,panic被net/http自带的recover机制捕获

CAGeng commented 3 years ago

求讲跨域中间件,我是这样写的,但是失败了:


=========================cors.go====================================
import "fmt"

func CORSMiddleware() HandlerFunc {
    return func(c *Context) {
        fmt.Print("1")
        c.Writer.Header().Set("Access-Control-Allow-Origin", "*")
        c.Writer.Header().Set("Access-Control-Allow-Credentials", "true")
        c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, accept, origin, Cache-Control, X-Requested-With")
        c.Writer.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS, GET, PUT")

        fmt.Print("2")

        if c.Req.Method == "OPTIONS" {
            c.Fail(204,"cors err")
            fmt.Print("err3")
            return
        }

        c.Next()
    }
}

============================main.go==================================
r.Use(Gouwa.CORSMiddleware())
puck1006 commented 3 years ago

recovery中间键是不是注册在logger中间键前面会好一些

JohnBing commented 3 years ago

看完了gee-web,十分收益,感谢博主!

Chadnon commented 3 years ago

谢谢

callmePicacho commented 3 years ago

完结撒兔兔,谢谢大佬

dashuaiduan commented 3 years ago

/panic 并不会宕机啊。。只是这个handler报错 其他handler 正常运行啊 为啥..

joewongex commented 2 years ago

官方推荐使用CallersFrames来获取调用栈信息

func trace(message string) string {
    var pcs [32]uintptr
    n := runtime.Callers(3, pcs[:])

    var str strings.Builder
    str.WriteString(message + "\nTraceback:")

    frames := runtime.CallersFrames(pcs[:n])
    for {
        frame, more := frames.Next()
        str.WriteString(fmt.Sprintf("\n\t%s:%d", frame.File, frame.Line))
        if !more {
            break
        }
    }

    return str.String()
}
Alex-Jee commented 2 years ago

文中main函数启动的时候,忘了写用Use把Recovery中间件注册进去了

fanandli commented 2 years ago

@Alex-Jee 文中main函数启动的时候,忘了写用Use把Recovery中间件注册进去了

Default里面写了

junbin-yang commented 2 years ago

参考博主的教程撸了一个练手项目github.com/junbin-yang/see,经过不断优化性能也优于gin。学到了不少东西。感谢感谢。

018429 commented 2 years ago

感谢

DurantVivado commented 2 years ago

谢谢@geektutu,有兴趣深入学习的小伙伴可以了解一下gin-vue-admin这个项目,绝对过瘾。

fatFire commented 2 years ago

参考博主的教程撸了一个练手项目github.com/junbin-yang/see,经过不断优化性能也优于gin。学到了不少东西。感谢感谢。

为什么你们的练手项目都能如此优秀

sphierex commented 2 years ago

受益匪浅,感谢博主。

luyi404 commented 2 years ago

感谢感谢感谢,感觉自己对GOLANG网络开发相关的理解比之前强多了555

taka250 commented 2 years ago

@wings-xue recorve 为什么一定要有 c.Next()? 没有就会报panic

因为defer recover机制只能针对于当前函数以及直接调用的函数可能参数的panic,所以在Recovery里面的c.Next()会执行下面这个handler

func(c *gee.Context) {
      names := []string{"geektutu"}
      c.String(http.StatusOK, names[100])
}

从而捕获到panic并恢复 如果没有c.Next(),则handler不是Recovery直接调用的函数,无法recover,panic被net/http自带的recover机制捕获

对的,一直next到最后一个handler会报错然后就会触发deff机制

taka250 commented 2 years ago

看了一遍感觉有问题,没有注册recovery的中间件,后来发现原来创建实例的时候创建的是default,里面已经注册过了

Serein404 commented 2 years ago

感谢geektutu,学到了好多!

joewongex commented 2 years ago

你好,你的邮件我已收到

LufeiCheng commented 2 years ago

多谢大佬无私分享,目前受益良多👍🏻

JaydenChang commented 2 years ago

@ayuayue

@geektutu @ayuayue 这个错误是故意设计的,下标越界触发panic。

触发了panic,其他路由可以正常返回,但是触发panic没有返回json,正常吗

老哥你看看你的router.go里面的handle函数有没有写错,我下午出现你的那个情况,也没有返回json,后面检查发现是handle那里有句话写错了

daohengdao commented 2 years ago

写完了,感谢博主,受益匪浅qwq

qbmiller commented 1 year ago

感谢,大半年前收藏后, 现在才看 ..后悔看的晚了

Liyuchuan commented 1 year ago

感谢博主,跟着写了一遍,受益匪浅

joewongex commented 1 year ago

你好,你的邮件我已收到

DDLGitGzzhM commented 1 year ago

大三下册纠结于考研和实习,但是本身就对“学习”提不起兴趣 。 所以选择all in Go, 大一大二写了两年的Java ,基本都是对一些过时的技术的学习,或者就是一些CRUD 很基础也很繁琐的操作。自从转型Go之后, 发现学完基础语法之后就寸步难行,不管是从实习项目准备开始 还是从面试底层源码着手都十分无趣 , 因为golang的开源项目对我来说较为晦涩 。不过自从接触到《7天系列》 , 真的是深深的爱上了, 因为这更加注重逻辑的处理, 代码也十分精炼 。总之在我较为黑暗的时光 , 如路灯一样照亮了我后面的学习道路 , 受益匪浅 , 多谢大佬分享

Gaojc1111 commented 1 year ago

感谢大佬 就是最后六七节对我来说有点吃力哈哈

joewongex commented 1 year ago

你好,你的邮件我已收到

LucasZhanye commented 1 year ago

请教下兔兔,能不能分享下,这些系列都是兔兔先学习了gin等框架源码之后再自己输出嘛?

DDLGitGzzhM commented 1 year ago

请教下兔兔,能不能分享下,这些系列都是兔兔先学习了gin等框架源码之后再自己输出嘛?

不用哦,gin框架会用就行,预计就半天就会用gin了。这个项目是从0开始的,没必要预先了解太多gin底层源码

LucasZhanye commented 1 year ago

@DDLGitGzzhM

请教下兔兔,能不能分享下,这些系列都是兔兔先学习了gin等框架源码之后再自己输出嘛?

不用哦,gin框架会用就行,预计就半天就会用gin了。这个项目是从0开始的,没必要预先了解太多gin底层源码

哈哈。你可能理解错我的意思,我的想法是想了解兔兔的学习方式,如何才能向兔兔一样优秀,向他学习

DDLGitGzzhM commented 1 year ago

@DDLGitGzzhM

请教下兔兔,能不能分享下,这些系列都是兔兔先学习了gin等框架源码之后再自己输出嘛?

不用哦,gin框架会用就行,预计就半天就会用gin了。这个项目是从0开始的,没必要预先了解太多gin底层源码

哈哈。你可能理解错我的意思,我的想法是想了解兔兔的学习方式,如何才能向兔兔一样优秀,向他学习

➡️🤡⬅️

Fencent commented 11 months ago

完结撒花,蟹蟹兔兔。第6、7天的内容感觉我是笨比(哭

joewongex commented 11 months ago

你好,你的邮件我已收到

Xienqing commented 9 months ago

2024-01-08 Gee框架1