blog icon indicating copy to clipboard operation
blog copied to clipboard

Go语言动手写Web框架 - Gee第一天 http.Handler | 极客兔兔

Open geektutu opened this issue 6 years ago • 55 comments

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框架处理。

geektutu avatar Aug 11 '19 18:08 geektutu

谢谢站主提供的项目经验,我有个问题不是很懂,网上查了资料也没有找到,http.ListenAndServe(":9999", engine)第二个参数是一个interface类型,里面有有一个ServeHTTP()方法,您代码中传入了一个结构体里面有一个ServeHTTP()方法,但是并没有调用啊,怎么就执行了。结构体不是应该先赋值给接口,接口才能够调用结构体中的方法吗。在下才疏学浅,想了2天,查了百度,还是觉得迷迷糊糊的,希望大神能够赐教,感激不尽

ccmzd avatar Mar 06 '20 01:03 ccmzd

@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 avatar Mar 06 '20 01:03 geektutu

@geektutu 非常感谢,我理解了

ccmzd avatar Mar 06 '20 01:03 ccmzd

第一天get,学框架的同时学习go。主要学习到:1. struct添加method 2. go mod 使用

ppd0705 avatar Apr 26 '20 10:04 ppd0705

博主文章写得真好,默默学习膜拜一波

JIACHENG135 avatar Jun 30 '20 00:06 JIACHENG135

博主写的真的是太赞了👍

建议博主把

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

maogou avatar Jul 05 '20 04:07 maogou

跪谢大佬的教程,在google搜索出来的web实例教程大多都是用标准库写一个简易web应用,想进阶却难以突破,直到看见大佬这份框架教程。

SilverShaded avatar Oct 21 '20 09:10 SilverShaded

@maogou 非常感谢你的建议,下次更新的时候我改一下,这里确实是忘记设置返回码了,不标准。

@tumaowolf 感谢你的认可,web 是第一期,后面还有三期~

geektutu avatar Oct 22 '20 04:10 geektutu

太强了,谢谢,财大牛皮😃

fangbaogang avatar Nov 18 '20 09:11 fangbaogang

@fangbaogang 感谢认可~ 😁

geektutu avatar Nov 22 '20 14:11 geektutu

正想学学http 相关知识, 看了第一天就感觉很好. 感谢tutu. 赞赏支持了下.

wzy2687 avatar Dec 17 '20 06:12 wzy2687

@wzy2687 感谢你的支持和赞赏 😸,希望能对你有用~

geektutu avatar Dec 17 '20 07:12 geektutu

大佬牛批,看你的文章真的通俗易懂,能让小白看懂的文章真的赞,跟读go语言高级编程第一章一样的感觉,爽,谢谢tutu

Fxskyzz avatar Dec 18 '20 02:12 Fxskyzz

@chocolateszz 感谢你的认可,通俗易懂是这个系列的终极目的~

geektutu avatar Dec 19 '20 12:12 geektutu

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

baoyixiang avatar Dec 22 '20 09:12 baoyixiang

mark 跟进学习

mesiyar avatar Dec 30 '20 09:12 mesiyar

@mesiyar 希望有所收获,ღ( ´・ᴗ・` )比心

geektutu avatar Dec 31 '20 14:12 geektutu

谢谢站主。最近打算学go,看了tour of go之后就过来跟你的教程啦

AcVoyager avatar Jan 08 '21 01:01 AcVoyager

@AcVoyager 嗯,加油,希望对你有帮助~

geektutu avatar Jan 11 '21 12:01 geektutu

@CaocaoWym 谢谢站主提供的项目经验,我有个问题不是很懂,网上查了资料也没有找到,http.ListenAndServe(":9999", engine)第二个参数是一个interface类型,里面有有一个ServeHTTP()方法,您代码中传入了一个结构体里面有一个ServeHTTP()方法,但是并没有调用啊,怎么就执行了。结构体不是应该先赋值给接口,接口才能够调用结构体中的方法吗。在下才疏学浅,想了2天,查了百度,还是觉得迷迷糊糊的,希望大神能够赐教,感激不尽

因为这个结构体有个方法已经实现了SeverHTTP,也就是说engine实现了Handler接口,故可以直接调用了

ghost avatar Jan 18 '21 07:01 ghost

谢谢大佬这一系列!

suibianmzl avatar Jan 23 '21 07:01 suibianmzl

@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

Shawn-fung avatar Jan 27 '21 03:01 Shawn-fung

这一章跳下一章的链接对不上

hevi1991 avatar Jan 28 '21 03:01 hevi1991

我测试的时候发现第一个 example 不会报 404,这和第二个 example 不一样。 查了下文档,原来默认使用的 ServerMux 有特殊的模式匹配规则。

ryan4yin avatar Jan 28 '21 05:01 ryan4yin

我是一只运维,对go初学很有帮助。感谢兔兔。

ryetan avatar Feb 15 '21 10:02 ryetan

也就是说,只要传入任何实现了 ServerHTTP 【接口】的实例。这里【接口】应该改成方法吧。

nm2006717 avatar Mar 14 '21 16:03 nm2006717

@nm2006717 也就是说,只要传入任何实现了 ServerHTTP 【接口】的实例。这里【接口】应该改成方法吧。 接口 = &类型 (该类型实现了接口中的所有方法),接口和具体方法的实现是这样传递的,方法由调用者去保证,ServeHttp定义的就是 type Handler interface { ServeHTTP(ResponseWriter, *Request) } 接口本来就是一个函数指针类型的集合

Lzu-Alisha avatar Mar 14 '21 17:03 Lzu-Alisha

如果有学过springmvc的同学,可以发现这里的engine就是就是dispatchservlet

yudidi avatar Apr 19 '21 10:04 yudidi

请问,还是需要引入gee框架吗?谢谢

Kimgtb avatar Apr 24 '21 06:04 Kimgtb

go.mod我这样写还是找不到依赖,麻烦问一下各位大佬知道这个怎么做吗

schinapi avatar Jul 11 '21 09:07 schinapi