Open geektutu opened 5 years ago
谢谢站主提供的项目经验,我有个问题不是很懂,网上查了资料也没有找到,http.ListenAndServe(":9999", engine)第二个参数是一个interface类型,里面有有一个ServeHTTP()方法,您代码中传入了一个结构体里面有一个ServeHTTP()方法,但是并没有调用啊,怎么就执行了。结构体不是应该先赋值给接口,接口才能够调用结构体中的方法吗。在下才疏学浅,想了2天,查了百度,还是觉得迷迷糊糊的,希望大神能够赐教,感激不尽
@MasterCl 第二个参数类型是接口类型 http.Handler
,Handler
的定义博文中已经贴了,是从 http
的源码中找到的。
type Handler interface {
ServeHTTP(w ResponseWriter, r *Request)
}
func ListenAndServe(address string, h Handler) error
在 Go 语言中,实现了接口方法的 struct 都可以强制转换为接口类型。你可以这么写:
handler := (http.Handler)(engine) // 手动转换为借口类型
log.Fatal(http.ListenAndServe(":9999", handler))
然后,ListenAndServe
方法里面会去调用 handler.ServeHTTP()
方法,你感兴趣,可以在 http 的源码中找到调用的地方。但是这么写是多余的,传参时,会自动进行参数转换的。所以直接传入engine 即可。
@geektutu 非常感谢,我理解了
第一天get,学框架的同时学习go。主要学习到:1. struct添加method 2. go mod 使用
博主文章写得真好,默默学习膜拜一波
博主写的真的是太赞了👍
建议博主把
func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) {
key := req.Method + "-" + req.URL.Path
if handler, ok := engine.router[key]; ok {
handler(w, req)
} else {
fmt.Fprintf(w, "404 NOT FOUND: %s\n", req.URL)
}
}
修改为
func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) {
key := req.Method + "-" + req.URL.Path
if handler, ok := engine.router[key]; ok {
handler(w, req)
} else {
w.WriteHeader(http.StatusNotFound)
fmt.Fprintf(w, "404 NOT FOUND: %s\n", req.URL)
}
}
跪谢大佬的教程,在google搜索出来的web实例教程大多都是用标准库写一个简易web应用,想进阶却难以突破,直到看见大佬这份框架教程。
@maogou 非常感谢你的建议,下次更新的时候我改一下,这里确实是忘记设置返回码了,不标准。
@tumaowolf 感谢你的认可,web 是第一期,后面还有三期~
太强了,谢谢,财大牛皮😃
@fangbaogang 感谢认可~ 😁
正想学学http 相关知识, 看了第一天就感觉很好. 感谢tutu. 赞赏支持了下.
@wzy2687 感谢你的支持和赞赏 😸,希望能对你有用~
大佬牛批,看你的文章真的通俗易懂,能让小白看懂的文章真的赞,跟读go语言高级编程第一章一样的感觉,爽,谢谢tutu
@chocolateszz 感谢你的认可,通俗易懂是这个系列的终极目的~
@CaocaoWym 谢谢站主提供的项目经验,我有个问题不是很懂,网上查了资料也没有找到,http.ListenAndServe(":9999", engine)第二个参数是一个interface类型,里面有有一个ServeHTTP()方法,您代码中传入了一个结构体里面有一个ServeHTTP()方法,但是并没有调用啊,怎么就执行了。结构体不是应该先赋值给接口,接口才能够调用结构体中的方法吗。在下才疏学浅,想了2天,查了百度,还是觉得迷迷糊糊的,希望大神能够赐教,感激不尽
这个是标准库里的逻辑吧,第二个参数传nil的话,标准库里默认用DefaultServeMux这个接口,传了你自定义的,标准库就调用你自定义的。if xx == nil 判断下就知道了。 我看了下源码
func (sh serverHandler) ServeHTTP(rw ResponseWriter, req *Request) {
handler := sh.srv.Handler
if handler == nil {
handler = DefaultServeMux
}
if req.RequestURI == "*" && req.Method == "OPTIONS" {
handler = globalOptionsHandler{}
}
handler.ServeHTTP(rw, req)
}
mark 跟进学习
@mesiyar 希望有所收获,ღ( ´・ᴗ・` )比心
谢谢站主。最近打算学go,看了tour of go之后就过来跟你的教程啦
@AcVoyager 嗯,加油,希望对你有帮助~
@CaocaoWym 谢谢站主提供的项目经验,我有个问题不是很懂,网上查了资料也没有找到,http.ListenAndServe(":9999", engine)第二个参数是一个interface类型,里面有有一个ServeHTTP()方法,您代码中传入了一个结构体里面有一个ServeHTTP()方法,但是并没有调用啊,怎么就执行了。结构体不是应该先赋值给接口,接口才能够调用结构体中的方法吗。在下才疏学浅,想了2天,查了百度,还是觉得迷迷糊糊的,希望大神能够赐教,感激不尽
因为这个结构体有个方法已经实现了SeverHTTP,也就是说engine实现了Handler接口,故可以直接调用了
谢谢大佬这一系列!
@geektutu @MasterCl 第二个参数类型是接口类型
http.Handler
,Handler
的定义博文中已经贴了,是从http
的源码中找到的。type Handler interface { ServeHTTP(w ResponseWriter, r *Request) } func ListenAndServe(address string, h Handler) error
在 Go 语言中,实现了接口方法的 struct 都可以强制转换为接口类型。你可以这么写:
handler := (http.Handler)(engine) // 手动转换为借口类型 log.Fatal(http.ListenAndServe(":9999", handler))
然后,
ListenAndServe
方法里面会去调用handler.ServeHTTP()
方法,你感兴趣,可以在 http 的源码中找到调用的地方。但是这么写是多余的,传参时,会自动进行参数转换的。所以直接传入engine 即可。
是否可以理解为:自己重写了ServeHTTP方法,所以默认会自动调用重写后的ServeHTTP
这一章跳下一章的链接对不上
我测试的时候发现第一个 example 不会报 404,这和第二个 example 不一样。 查了下文档,原来默认使用的 ServerMux 有特殊的模式匹配规则。
我是一只运维,对go初学很有帮助。感谢兔兔。
也就是说,只要传入任何实现了 ServerHTTP 【接口】的实例。这里【接口】应该改成方法吧。
@nm2006717 也就是说,只要传入任何实现了 ServerHTTP 【接口】的实例。这里【接口】应该改成方法吧。 接口 = &类型 (该类型实现了接口中的所有方法),接口和具体方法的实现是这样传递的,方法由调用者去保证,ServeHttp定义的就是 type Handler interface { ServeHTTP(ResponseWriter, *Request) } 接口本来就是一个函数指针类型的集合
如果有学过springmvc的同学,可以发现这里的engine就是就是dispatchservlet
请问,还是需要引入gee框架吗?谢谢
go.mod我这样写还是找不到依赖,麻烦问一下各位大佬知道这个怎么做吗
正愁没啥参考学习的文章,刚好看到这篇文章,受益匪浅,感谢大佬!!
学习了
作为一个新手记录一下本次学习下来的收获: 从设计的角度来学习
学习到的实现方法
@schinapi go.mod我这样写还是找不到依赖,麻烦问一下各位大佬知道这个怎么做吗
import的时候,使用从项目名称开始的路径吧
个人小结,希望大家给我补充一下
首先做了什么 : 本部分基于net/http基础库进行了二次封装。依据http.ListenAndServe监听了端口,将所有请求交给handler进行统一处理的特点。 对于不同的请求路径及handler,通过map与统一的handler type进行绑定,只需要http.ListenAndServe就可以处理所有请求, 不需要再像基础库那样,对于不同的请求路径写了多个http.HandlerFunc进行处理。
好处: 统一的请求入口,就可以进行统一的处理,如日志,拦截器等。
楼主是真的厉害 感谢分享~ 学完Python再学Go感觉很亲切
从go夜读过来的,发现了宝藏博主.学习了
@geektutu @maogou 非常感谢你的建议,下次更新的时候我改一下,这里确实是忘记设置返回码了,不标准。
@tumaowolf 感谢你的认可,web 是第一期,后面还有三期~
但是没改呀。。。。
非常感谢楼主 很清晰
请问为什么构造POST方法就会返回404呢,用GET是正常的。下面的r.GET
换成r.POST
就返回404
func main() {
r := gee.New()
r.GET("/", func(w http.ResponseWriter, req *http.Request) {
fmt.Fprintf(w, "URL.Path = %q\n", req.URL.Path)
})
r.GET("/hello", func(w http.ResponseWriter, req *http.Request) {
for k, v := range req.Header {
fmt.Fprintf(w, "Header[%q] = %q\n", k, v)
}
})
r.Run(":9999")
}
请问下格式化字符串中的 %q 是什么意思,以前没有用过,了解下。
请问下格式化字符串中的 %q 是什么意思,以前没有用过,了解下。
了解了,是以 golang 中字面值的形式打印的
@SharkLJ 请问为什么构造POST方法就会返回404呢,用GET是正常的。下面的
r.GET
换成r.POST
就返回404func main() { r := gee.New() r.GET("/", func(w http.ResponseWriter, req *http.Request) { fmt.Fprintf(w, "URL.Path = %q\n", req.URL.Path) }) r.GET("/hello", func(w http.ResponseWriter, req *http.Request) { for k, v := range req.Header { fmt.Fprintf(w, "Header[%q] = %q\n", k, v) } }) r.Run(":9999") }
测试的时候有改成post吗?像下面这样
curl -X POST http://localhost:8088
多谢大佬分享教程,对新学习Golang的小伙伴太有帮助了,非常适合用来实战!!!
@schinapi go.mod我这样写还是找不到依赖,麻烦问一下各位大佬知道这个怎么做吗
同找不到,请问怎么解决,网上没找到很好的解决方案.
@maogou 博主写的真的是太赞了👍
建议博主把
func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) { key := req.Method + "-" + req.URL.Path if handler, ok := engine.router[key]; ok { handler(w, req) } else { fmt.Fprintf(w, "404 NOT FOUND: %s\n", req.URL) } }
修改为
func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) { key := req.Method + "-" + req.URL.Path if handler, ok := engine.router[key]; ok { handler(w, req) } else { w.WriteHeader(http.StatusNotFound) fmt.Fprintf(w, "404 NOT FOUND: %s\n", req.URL) } }
为啥要这样改
@MachineGunLin
@maogou 博主写的真的是太赞了👍
建议博主把
func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) { key := req.Method + "-" + req.URL.Path if handler, ok := engine.router[key]; ok { handler(w, req) } else { fmt.Fprintf(w, "404 NOT FOUND: %s\n", req.URL) } }
修改为
func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) { key := req.Method + "-" + req.URL.Path if handler, ok := engine.router[key]; ok { handler(w, req) } else { w.WriteHeader(http.StatusNotFound) fmt.Fprintf(w, "404 NOT FOUND: %s\n", req.URL) } }
为啥要这样改
需要设置响应请求的状态码
卧槽,我第一次评论,简直太牛逼了博主
来了,肥猫我啊,狠狠的跟tutu学!
https://geektutu.com/post/gee-day1.html
7天用 Go语言 从零实现Web框架教程(7 days implement golang web framework from scratch tutorial),用 Go语言/golang 动手写Web框架,从零实现一个Web框架,从零设计一个Web框架。本文介绍了Go标准库 net/http 和 http.Handler 接口的使用,拦截所有的 HTTP 请求,交给Gee框架处理。